home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / util / misc / csh547src.lha / comm1.c next >
C/C++ Source or Header  |  1995-09-01  |  66KB  |  2,918 lines

  1. /*
  2.  * COMM1.C
  3.  *
  4.  * Matthew Dillon, August 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* comm1.c */
  16. static void display_file(char *filestr);
  17. static int search_file( long mask, char *s, char *fullpath );
  18. static int rm_file    ( long mask, char *s, char *fullpath );
  19. static int quicksearch(char *name, int nocasedep, char *pattern);
  20. static void setsystemtime(struct DateStamp *ds);
  21. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  22.  
  23. void lformat( char *s, char *d, FILEINFO *info );
  24.  
  25. extern int has_wild;
  26.  
  27. int
  28. do_sleep( void )
  29. {
  30.     long ticks,secs;
  31.  
  32.     if (ac == 2) {
  33.         if (options&1) {    /* ticks */
  34.             ticks  = atoi(av[1]);
  35.             secs   = ticks / 50;
  36.             ticks -= secs*50;
  37.         }
  38.         else {    /* seconds */
  39.             secs   = atoi(av[1]);
  40.             ticks  = 0;
  41.         }
  42.  
  43.         if (ticks>0)
  44.             Delay(ticks);
  45.  
  46.         while (secs>0 && !CHECKBREAK()) {
  47.             Delay(50);
  48.             secs--;
  49.         }
  50.     }
  51.  
  52.     return 0;
  53. }
  54.  
  55. #if 0
  56. /* AMK: if you change this, you must change do_chmod() also!! */
  57. int
  58. do_protect( void )
  59. {
  60.     static char flags[]="DEWRAPSH";
  61.     char *s, *p;
  62.     long setmask=0, clrmask=0xFF, mask;
  63.     int  i, mode=0, stat;
  64.     DPTR *dp;
  65.  
  66.     for (s=strupr(av[--ac]); *s; s++) {
  67.         if (*s=='=') { mode=0; continue; }
  68.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  69.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  70.  
  71.         if (*s=='X') *s='E';
  72.         if (p=index(flags, *s)) {
  73.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  74.             if( mode==1 ) setmask|= 1<<(p-flags);
  75.             if( mode==2 ) clrmask|= 1<<(p-flags);
  76.         } else {
  77.             ierror(av[ac],500);
  78.             return 20;
  79.         }
  80.     }
  81.  
  82.     for (i=1; i<ac; i++) {
  83.         if( (dp=dopen(av[i],&stat))) {
  84.             mask = dp->fib->fib_Protection ^ 0x0F;
  85.             mask&=~clrmask;
  86.             mask|= setmask;
  87.             dclose(dp);
  88.             if( !setProtection( av[i], mask ^ 0x0F))
  89.                 pError(av[i]);
  90.         } else
  91.             pError(av[i]);
  92.     }
  93.     return 0;
  94. }
  95. #endif
  96.  
  97. /* AMK: same as do_protect, but flags now as first argument */
  98. #if 0
  99. int
  100. do_chmod( void )
  101. {
  102.     static char flags[]="DEWRAPSH";
  103.     char *s, *p;
  104.     long setmask=0, clrmask=0xFF, mask;
  105.     int  i, mode=0, stat;
  106.     DPTR *dp;
  107.  
  108.     for (s=strupr(av[1]); *s; s++) {       /* AMK: changed */
  109.         if (*s=='=') { mode=0; continue; }
  110.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  111.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  112.  
  113.         if (*s=='X') *s='E';
  114.         if (p=index(flags, *s)) {
  115.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  116.             if( mode==1 ) setmask|= 1<<(p-flags);
  117.             if( mode==2 ) clrmask|= 1<<(p-flags);
  118.         } else {
  119.             ierror(av[1],500);     /* AMK: changed */
  120.             return 20;
  121.         }
  122.     }
  123.  
  124.     for (i=2; i<ac; i++) {                 /* AMK: changed */
  125.         if( (dp=dopen(av[i],&stat))) {
  126.             mask = dp->fib->fib_Protection ^ 0x0F;
  127.             mask&=~clrmask;
  128.             mask|= setmask;
  129.             dclose(dp);
  130.             if( !setProtection( av[i], mask ^ 0x0F))
  131.                 pError(av[i]);
  132.         } else
  133.             pError(av[i]);
  134.     }
  135.     return 0;
  136. }
  137. #endif
  138.  
  139. #define FIBB_HOLD 7
  140. #define FIBF_HOLD (1<<FIBB_HOLD)
  141.  
  142. int do_chmod_internal(long arg_begin,long arg_end,long arg_flags)
  143. {
  144.     char *s;
  145.     LONG mask;
  146.     int  i, stat;
  147.     DPTR *dp;
  148.     BOOL do_user=FALSE,do_group=FALSE,do_other=FALSE,do_default=TRUE;
  149.     BOOL do_incl=FALSE,do_excl=FALSE,do_set=TRUE;
  150.  
  151.     /*strlwr(av[1]);*/
  152.  
  153.     for (i=arg_begin; i<arg_end; i++) {  /* all arguments except 'arg_flags' */
  154.  
  155.         if( (dp=dopen(av[i],&stat))) {
  156.             mask = dp->fib->fib_Protection;
  157.             dclose(dp);
  158.  
  159.             s = av[arg_flags];
  160.  
  161.             if (strchr(s,'+') || strchr(s,'-') || strchr(s,'=')) {
  162.  
  163.                 while (*s && !strchr("+-=",*s)) {
  164.                     switch (*s) {
  165.                     case 'u': do_user  = TRUE; break;
  166.                     case 'g': do_group = TRUE; break;
  167.                     case 'o': do_other = TRUE; break;
  168.                     case 'a': do_user  =
  169.                               do_group = 
  170.                               do_other = TRUE; break;
  171.                     default : ierror(av[1],500); return 20;
  172.                     }
  173.                     do_default = FALSE;
  174.                     ++s;
  175.                 }
  176.  
  177.                 do_set = FALSE;
  178.  
  179.                 switch (*s) {
  180.                 case '+': do_incl = TRUE; break;
  181.                 case '-': do_excl = TRUE; break;
  182.                 case '=': do_set  = TRUE; break;
  183.                 default : ierror(av[1],500); return 20;
  184.                 }
  185.  
  186.                 ++s;
  187.  
  188.             }
  189.  
  190.             if (do_default) {
  191.                 do_user=TRUE;
  192.             }
  193.  
  194.             if (do_set) {
  195.                 do_incl = TRUE;
  196.                 mask = FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
  197.             }
  198.  
  199.             mask &= (~FIBF_ARCHIVE);
  200.  
  201.             while (*s) {
  202.                 switch (*s) {
  203.                 case 'r' :
  204.                            if (do_incl) {
  205.                              if (do_user)  mask &= (~FIBF_READ);
  206.                              if (do_group) mask |= FIBF_GRP_READ;
  207.                              if (do_other) mask |= FIBF_OTR_READ;
  208.                            }
  209.                            else {
  210.                              if (do_user)  mask |= FIBF_READ;
  211.                              if (do_group) mask &= (~FIBF_GRP_READ);
  212.                              if (do_other) mask &= (~FIBF_OTR_READ);
  213.                            }
  214.                            break;
  215.                 case 'w' :
  216.                            if (do_incl) {
  217.                              if (do_user)  mask &= (~FIBF_WRITE);
  218.                              if (do_group) mask |= FIBF_GRP_WRITE;
  219.                              if (do_other) mask |= FIBF_OTR_WRITE;
  220.                            }
  221.                            else {
  222.                              if (do_user)  mask |= FIBF_WRITE;
  223.                              if (do_group) mask &= (~FIBF_GRP_WRITE);
  224.                              if (do_other) mask &= (~FIBF_OTR_WRITE);
  225.                            }
  226.                            break;
  227.                 case 'e' :
  228.                 case 'x' :
  229.                            if (do_incl) {
  230.                              if (do_user)  mask &= (~FIBF_EXECUTE);
  231.                              if (do_group) mask |= FIBF_GRP_EXECUTE;
  232.                              if (do_other) mask |= FIBF_OTR_EXECUTE;
  233.                            }
  234.                            else {
  235.                              if (do_user)  mask |= FIBF_EXECUTE;
  236.                              if (do_group) mask &= (~FIBF_GRP_EXECUTE);
  237.                              if (do_other) mask &= (~FIBF_OTR_EXECUTE);
  238.                            }
  239.                            break;
  240.                 case 'd' :
  241.                            if (do_incl) {
  242.                              if (do_user)  mask &= (~FIBF_DELETE);
  243.                              if (do_group) mask |= FIBF_GRP_DELETE;
  244.                              if (do_other) mask |= FIBF_OTR_DELETE;
  245.                            }
  246.                            else {
  247.                              if (do_user)  mask |= FIBF_DELETE;
  248.                              if (do_group) mask &= (~FIBF_GRP_DELETE);
  249.                              if (do_other) mask &= (~FIBF_OTR_DELETE);
  250.                            }
  251.                            break;
  252.                 case 'a' :
  253.                            if (do_incl)
  254.                              mask |= FIBF_ARCHIVE;
  255.                            else
  256.                              mask &= (~FIBF_ARCHIVE);
  257.                            break;
  258.                 case 'p' :
  259.                            if (do_incl)
  260.                              mask |= FIBF_PURE;
  261.                            else
  262.                              mask &= (~FIBF_PURE);
  263.                            break;
  264.                 case 's' :
  265.                            if (do_incl)
  266.                              mask |= FIBF_SCRIPT;
  267.                            else
  268.                              mask &= (~FIBF_SCRIPT);
  269.                            break;
  270.                 case 'h' :
  271.                            if (do_incl)
  272.                              mask |= FIBF_HOLD;
  273.                            else
  274.                              mask &= (~FIBF_HOLD);
  275.                            break;
  276.                 default  :
  277.                            ierror(av[1],500);
  278.                            return 20;
  279.                 }
  280.                 ++s;
  281.             }
  282.  
  283.             if( !setProtection( av[i], mask ))
  284.                 pError(av[i]);
  285.         }
  286.         else
  287.             pError(av[i]);
  288.     }
  289.  
  290.     return 0;
  291. }
  292.  
  293. int do_protect(void)
  294. {
  295.     return do_chmod_internal(1,ac-1,ac-1);
  296. }
  297.  
  298. int do_chmod(void)
  299. {
  300.     return do_chmod_internal(2,ac,1);
  301. }
  302.  
  303.  
  304.  
  305. int do_chown(void)
  306. {
  307.     LONG mask;  /* 2x UWORD */
  308.     UWORD new_uid,new_gid = 0;
  309.     int  i, stat;
  310.     DPTR *dp;
  311.  
  312. #ifdef MULTIUSER_SUPPORT
  313.     struct muUserInfo *info;
  314.     struct muUserInfo *res;
  315.  
  316.     if (muBase) {
  317.         if (info = muAllocUserInfo()) {
  318.             if (isdigit(av[1][0])) {
  319.                 new_uid = myatoi(av[1],0,65535);
  320.                 if (atoierr) {
  321.                     fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  322.                     muFreeUserInfo(info);
  323.                     return 20;
  324.                 }
  325.                 info->uid = new_uid;
  326.                 res = muGetUserInfo(info,muKeyType_uid);
  327.                 new_gid = info->gid;
  328.             }
  329.             else {
  330.                 if (strlen(av[1]) > muUSERIDSIZE-1) {
  331.                     fprintf(stderr,"%s: string too long for a User-ID.\n",av[1]);
  332.                     muFreeUserInfo(info);
  333.                     return 20;
  334.                 }
  335.                 strcpy(info->UserID,av[1]);
  336.                 if (!(res = muGetUserInfo(info,muKeyType_UserID))) {
  337.                     fprintf(stderr,"%s: no valid user.\n",av[1]);
  338.                     muFreeUserInfo(info);
  339.                     return 20;
  340.                 }
  341.                 new_uid = info->uid;
  342.                 new_gid = info->gid;
  343.             }
  344.             muFreeUserInfo(info);
  345.         }
  346.         else {
  347.             fprintf(stderr,"Not enough memory.\n");
  348.             return 20;
  349.         }
  350.     }
  351.     else {
  352.         new_uid = myatoi(av[1],0,65535);
  353.         if (atoierr) {
  354.             fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  355.             return 20;
  356.         }
  357.     }
  358. #else
  359.     new_uid = myatoi(av[1],0,65535);
  360.     if (atoierr) {
  361.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  362.         return 20;
  363.     }
  364. #endif /* MULTIUSER_SUPPORT */
  365.  
  366.     for (i=2; i<ac; i++) {  /* all arguments except first */
  367.  
  368.         if( (dp=dopen(av[i],&stat))) {
  369.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  370.             mask = dp->fib->fib_OwnerGID + (new_uid<<16);
  371.             if (options&1)    /* also set GID to primary group */
  372.                 mask = new_gid + (new_uid<<16);
  373.             else
  374.                 mask = dp->fib->fib_OwnerGID + (new_uid<<16);
  375.             dclose(dp);
  376.  
  377.             /*printf("  new mask: %ld\n",mask);*/
  378.             if (DOSBase->dl_lib.lib_Version<39) {
  379.                 if( !SetOwner37( av[i], mask ))
  380.                     pError(av[i]);
  381.             }
  382.             else {
  383.                 if( !SetOwner( av[i], mask ))
  384.                     pError(av[i]);
  385.             }
  386.         }
  387.         else
  388.             pError(av[i]);
  389.     }
  390.  
  391.     return 0;
  392. }
  393.  
  394.  
  395.  
  396. int do_chgrp(void)
  397. {
  398.     LONG mask;  /* 2x UWORD */
  399.     UWORD new_gid;
  400.     int  i, stat;
  401.     DPTR *dp;
  402.  
  403. #ifdef MULTIUSER_SUPPORT
  404.     struct muGroupInfo *info;
  405.     struct muGroupInfo *res;
  406.  
  407.     if (muBase && !isdigit(av[1][0])) {
  408.         if (info = muAllocGroupInfo()) {
  409.             if (strlen(av[1]) > muGROUPIDSIZE-1) {
  410.                 fprintf(stderr,"%s: string too long for a Group-ID.\n",av[1]);
  411.                 muFreeGroupInfo(info);
  412.                 return 20;
  413.             }
  414.             strcpy(info->GroupID,av[1]);
  415.             if (!(res = muGetGroupInfo(info,muKeyType_GroupID))) {
  416.                 fprintf(stderr,"%s: no valid group.\n",av[1]);
  417.                 muFreeGroupInfo(info);
  418.                 return 20;
  419.             }
  420.             new_gid = info->gid;
  421.             muFreeGroupInfo(info);
  422.         }
  423.         else {
  424.             fprintf(stderr,"Not enough memory.\n");
  425.             return 20;
  426.         }
  427.     }
  428.     else {
  429.         new_gid = myatoi(av[1],0,65535);
  430.         if (atoierr) {
  431.             fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  432.             return 20;
  433.         }
  434.     }
  435. #else
  436.     new_gid = myatoi(av[1],0,65535);
  437.     if (atoierr) {
  438.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  439.         return 20;
  440.     }
  441. #endif /* MULTIUSER_SUPPORT */
  442.  
  443.     for (i=2; i<ac; i++) {  /* all arguments except first */
  444.  
  445.         if( (dp=dopen(av[i],&stat))) {
  446.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  447.             mask = (dp->fib->fib_OwnerUID<<16) + new_gid;
  448.             dclose(dp);
  449.  
  450.             /*printf("  new mask: %ld\n",mask);*/
  451.             if (DOSBase->dl_lib.lib_Version<39) {
  452.                 if( !SetOwner37( av[i], mask ))
  453.                     pError(av[i]);
  454.             }
  455.             else {
  456.                 if( !SetOwner( av[i], mask ))
  457.                     pError(av[i]);
  458.             }
  459.         }
  460.         else
  461.             pError(av[i]);
  462.     }
  463.  
  464.     return 0;
  465. }
  466.  
  467.  
  468.  
  469. #if 0
  470. int do_chown(void)
  471. {
  472.     LONG mask;  /* 2x UWORD */
  473.     UWORD new_id;
  474.     int  i, stat;
  475.     DPTR *dp;
  476.  
  477.     new_id = myatoi(av[1],0,65535);
  478.     if (atoierr) {
  479.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  480.         return 20;
  481.     }
  482.  
  483.     for (i=2; i<ac; i++) {  /* all arguments except first */
  484.  
  485.         if( (dp=dopen(av[i],&stat))) {
  486.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  487.             mask = dp->fib->fib_OwnerGID + (new_id<<16);
  488.             dclose(dp);
  489.  
  490.             /*printf("  new mask: %ld\n",mask);*/
  491.             if (DOSBase->dl_lib.lib_Version<39) {
  492.                 if( !SetOwner37( av[i], mask ))
  493.                     pError(av[i]);
  494.             }
  495.             else {
  496.                 if( !SetOwner( av[i], mask ))
  497.                     pError(av[i]);
  498.             }
  499.         }
  500.         else
  501.             pError(av[i]);
  502.     }
  503.  
  504.     return 0;
  505. }
  506.  
  507.  
  508.  
  509. int do_chgrp(void)
  510. {
  511.     LONG mask;  /* 2x UWORD */
  512.     UWORD new_id;
  513.     int  i, stat;
  514.     DPTR *dp;
  515.  
  516.     new_id = myatoi(av[1],0,65535);
  517.     if (atoierr) {
  518.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  519.         return 20;
  520.     }
  521.  
  522.     for (i=2; i<ac; i++) {  /* all arguments except first */
  523.  
  524.         if( (dp=dopen(av[i],&stat))) {
  525.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  526.             mask = (dp->fib->fib_OwnerUID<<16) + new_id;
  527.             dclose(dp);
  528.  
  529.             /*printf("  new mask: %ld\n",mask);*/
  530.             if (DOSBase->dl_lib.lib_Version<39) {
  531.                 if( !SetOwner37( av[i], mask ))
  532.                     pError(av[i]);
  533.             }
  534.             else {
  535.                 if( !SetOwner( av[i], mask ))
  536.                     pError(av[i]);
  537.             }
  538.         }
  539.         else
  540.             pError(av[i]);
  541.     }
  542.  
  543.     return 0;
  544. }
  545. #endif
  546.  
  547.  
  548.  
  549. int
  550. do_filenote( void )
  551. {
  552.     DPTR *dp;
  553.     char *note;
  554.     int i, stat;
  555.  
  556.     if( options&1 ) {
  557.         for( i=1; i<ac && !dobreak(); i++ )
  558.             if( dp=dopen( av[i], &stat )) {
  559.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  560.                 dclose( dp );
  561.             }
  562.     } else {
  563.         note=av[--ac];
  564.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  565.     }
  566.     return 0;
  567. }
  568.  
  569. int
  570. do_cat( void )
  571. {
  572.     FILE *fi;
  573.     int lctr, i, docr=0;
  574.     char buf[256], *l;
  575.  
  576.     prepscroll(0);
  577.     if (ac<=1) {
  578.         if (has_wild) { printf("No files matching\n"); return 20; }
  579.         lctr=0;
  580.         while (fgets(buf,256,stdin) && !dobreak()) {
  581.             if (options) printf("%4d ",++lctr);
  582.             quickscroll();
  583.             l=buf+strlen( buf )-1; docr=1;
  584.             if( l>=buf && *l=='\n' ) docr=0;
  585.             fputs(buf,stdout);
  586.         }
  587.     } else {
  588.         for (i=1; i<ac; i++)
  589.             if (fi = fopen (av[i], "r")) {
  590.                 lctr=0;
  591.                 while (fgets(buf,256,fi) && !dobreak()) {
  592.                     if (options&1) printf("%4d ",++lctr);
  593.                     quickscroll();
  594.                     l=buf+strlen( buf )-1; docr=1;
  595.                     if( l>=buf && *l=='\n' ) docr=0;
  596.                     fputs(buf,stdout); fflush(stdout);
  597.                 }
  598.                 fclose (fi);
  599.             } else
  600.                 pError(av[i]);
  601.     }
  602.     if ( docr && IsInteractive(Output()) )
  603.         putchar('\n');
  604.     return 0;
  605. }
  606.  
  607.  
  608.  
  609. char *add_simple_device(char *list,char *dev)
  610. {
  611.     char *new = NULL;
  612.  
  613.     if (list) {
  614.         if (new = malloc(strlen(dev)+strlen(list)+2)) {        /* null byte + \n */
  615.             strcpy(new,list);
  616.             strcat(new,dev);
  617.             strcat(new,"\n");
  618.             free(list);
  619.         }
  620.         else
  621.             new = list;
  622.     }
  623.     else {
  624.         if (new = malloc(strlen(dev)+2)) {            /* null byte + \n */
  625.             strcpy(new,dev);
  626.             strcat(new,"\n");
  627.         }
  628.     }
  629.  
  630.     return(new);
  631. }
  632.  
  633.  
  634.  
  635. void
  636. get_drives(char *buf)
  637. {
  638.     struct DosList *dl;
  639.     ULONG flags = LDF_DEVICES|LDF_READ;
  640.     char devname[256];
  641.     char **dev_list=NULL;
  642.     long i,dev_num=0;
  643.  
  644.     buf[0]=0;
  645.     if (dl=LockDosList(flags)) {
  646.         while (dl=NextDosEntry(dl,flags)) {
  647.             if (dl->dol_Task) {
  648.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  649.                 strcat(devname,":");
  650.                 add_array_list(&dev_list,&dev_num,devname);
  651.             }
  652.         }
  653.         UnLockDosList(flags);
  654.     }
  655.  
  656.     QuickSort(dev_list,dev_num);
  657.  
  658.     for(i=0; i<dev_num; i++) {
  659.         if (IsFileSystem(dev_list[i])) {
  660.             if (buf[0])
  661.                 strcat(buf,"\240");
  662.             strcat(buf,dev_list[i]);
  663.         }
  664.     }
  665.  
  666.     free_array_list(dev_list,dev_num);
  667. }
  668.  
  669. static char infobuf[100];
  670. static char namebuf[32];  /* AMK: old size was 12, too small for drive names */
  671.  
  672.  
  673. /* AMK: find last occurence of a character in a string */
  674. char *strlast(char *s,char c)
  675. {
  676.   char *p=NULL;
  677.   while(*s) {
  678.     if(*s==c)
  679.       p=s;
  680.     s++;
  681.   }
  682.   return(p);
  683. }
  684.  
  685.  
  686. char *
  687. drive_name( char *name )
  688. {
  689.     struct DosList *dl;
  690.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  691.     ULONG flags = LDF_DEVICES|LDF_READ;
  692.     char devname[256];
  693.     char **dev_list=NULL;
  694.     long i,dev_num=0;
  695.  
  696.     /* AMK: we want no self-modifying code */
  697.     strncpy( namebuf, name, 31 );   /* AMK: 30 chars device name + ':' */
  698.     namebuf[31] = '\0';             /* AMK: null-terminated */
  699.     if (dl=LockDosList(flags)) {
  700.         while (dl=NextDosEntry(dl,flags)) {
  701.             if (dl->dol_Task) {
  702.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  703.                 strcat(devname,":");
  704.                 add_array_list(&dev_list,&dev_num,devname);
  705.             }
  706.         }
  707.         UnLockDosList(flags);
  708.     }
  709.  
  710.     QuickSort(dev_list,dev_num);
  711.  
  712.     for(i=0; i<dev_num; i++) {
  713.         if (IsFileSystem(dev_list[i])) {
  714.             if ((struct MsgPort *)DeviceProc(dev_list[i])==proc)
  715.                 strcpy(namebuf,dev_list[i]);
  716.         }
  717.     }
  718.  
  719.     free_array_list(dev_list,dev_num);
  720.  
  721.     return namebuf;
  722. }
  723.  
  724. int
  725. do_info( void )
  726. {
  727.     struct DosList *dl;
  728.     ULONG flags = LDF_DEVICES|LDF_READ;
  729.     char devname[256];
  730.     char **dev_list=NULL;
  731.     long i,dev_num=0;
  732.  
  733.     if (options&2)
  734.         puts("Unit     Size  Block  Type   Used   Free Full Errs  Status    Name");
  735.     else
  736.         puts("Unit     Size  Bytes  Used Blk/Byte-Free Full Errs  Status    Name");
  737.  
  738.     if( ac==1 ) {
  739.         if (dl=LockDosList(flags)) {
  740.             while (dl=NextDosEntry(dl,flags)) {
  741.                 if (dl->dol_Task) {
  742.                     BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  743.                     strcat(devname,":");
  744.                     add_array_list(&dev_list,&dev_num,devname);
  745.                 }
  746.             }
  747.             UnLockDosList(flags);
  748.         }
  749.  
  750.         QuickSort(dev_list,dev_num);
  751.  
  752.         for(i=0; !dobreak() && i<dev_num; i++) {
  753.             if (IsFileSystem(dev_list[i])) {
  754.                 oneinfo(dev_list[i],0);
  755.             }
  756.         }
  757.  
  758.         free_array_list(dev_list,dev_num);
  759.     }
  760.     else {
  761.         for( i=1; i<ac; i++ )
  762.             oneinfo( drive_name( av[i] ), 0 );
  763.     }
  764.  
  765.     return 0;
  766. }
  767.  
  768.  
  769.  
  770. /* these defines are new in OS 3.x */
  771. #ifndef ID_FASTDIR_DOS_DISK
  772. #define ID_FASTDIR_DOS_DISK (0x444F5304L)
  773. #endif
  774. #ifndef ID_FASTDIR_FFS_DISK
  775. #define ID_FASTDIR_FFS_DISK (0x444F5305L)
  776. #endif
  777.  
  778.  
  779.  
  780. /* AMK: new mode==6 to suppress output if disk is not present */
  781. char *
  782. oneinfo( char *name, int mode )
  783. {
  784.     struct InfoData *info;
  785.     struct DevProc *devproc;
  786.     struct DeviceList *dl;
  787.     BPTR lock;
  788.     long size, free, freebl, blocks;
  789.     char buf[130], *state, *type;
  790.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  791.  
  792.     Myprocess->pr_WindowPtr = (APTR)(-1);
  793.  
  794.     if (!name) name="";
  795.  
  796.     if (mode<=1 || mode>=5)
  797.         strcpy(infobuf,"");
  798.     else
  799.         strcpy(infobuf,"0");
  800.  
  801.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  802.  
  803.     if (devproc=GetDeviceProc(name,NULL)) {
  804.         if (DoPkt(devproc->dvp_Port,ACTION_DISK_INFO,MKBADDR(info),NULL,NULL,NULL,NULL)==DOSTRUE) {
  805.             BOOL go_on = FALSE;
  806.             char *spclfmt;
  807. #if 0
  808.             if (!NameFromLock(lock, buf, 128L)) {
  809.                 fprintf(stderr,"csh.oneinfo: NameFromLock() failed\n");
  810.                 strcpy(buf,name);
  811.             }
  812.             if (p=strlast(buf,':')) *p = '\0';
  813.             /* AMK: we want the last occurence of ':', not the first;
  814.                     ':' and '/' are legal path name components !!
  815.                     (bug only in RAM: disk)
  816.             if (p=index(buf,':')) *p = '\0';
  817.             */
  818. #endif
  819.             switch (mode) {
  820.                 case 0:
  821.                     if (options&1)
  822.                         spclfmt = "";
  823.                     else
  824.                         spclfmt = "%-7s %s\n";
  825.                     break;
  826.                 case 1:
  827.                     spclfmt = "%s\240%s\n";
  828.                     break;
  829.                 case 2:
  830.                 case 3:
  831.                 case 4:
  832.                     spclfmt = "0";
  833.                     break;
  834.                 case 5:
  835.                     spclfmt = "";
  836.                     break;
  837.                 default:
  838.                     spclfmt = "";
  839.                     break;
  840.             }
  841.  
  842.             switch (info->id_DiskType) {
  843.                 case ID_UNREADABLE_DISK:
  844.                     sprintf(infobuf,spclfmt,name,"Unreadable disk");
  845.                     break;
  846.                 case ID_NOT_REALLY_DOS:
  847.                     sprintf(infobuf,spclfmt,name,"Not a DOS disk");
  848.                     break;
  849.                 case ID_KICKSTART_DISK:
  850.                     sprintf(infobuf,spclfmt,name,"Kickstart disk");
  851.                     break;
  852.                 case (0x42555359L):  /* 'BUSY' */
  853.                     sprintf(infobuf,spclfmt,name,"Disk is busy");
  854.                     break;
  855.                 case ID_NO_DISK_PRESENT:
  856.                     sprintf(infobuf,spclfmt,name,"No disk present");
  857.                     break;
  858.                 default:
  859.                     sprintf(infobuf,spclfmt,name,"Unknown disk type");
  860.                     go_on = TRUE;
  861.                     break;
  862.             }
  863.  
  864.             if (go_on && (lock=Lock(name,ACCESS_READ))) {
  865.                 UnLock(lock);
  866.                 /* note:  we call Lock() to be sure that the volume is readable */
  867.  
  868.                 switch(info->id_DiskType) {
  869.                     case ID_MSDOS_DISK:       type=" MSDOS"; break;
  870.                     case ID_DOS_DISK:         type="   OFS"; break;
  871.                     case ID_FFS_DISK:         type="   FFS"; break;
  872.                     case ID_INTER_DOS_DISK:   type="IN/OFS"; break;
  873.                     case ID_INTER_FFS_DISK:   type="  INTL"; break;
  874.                     case ID_FASTDIR_DOS_DISK: type="DC/OFS"; break;
  875.                     case ID_FASTDIR_FFS_DISK: type="  DCFS"; break;
  876.                     default:                  type="   n/a"; break;
  877.                 }
  878.  
  879.                 strcpy(buf,"n/a");
  880.                 if (dl = (struct DeviceList *)BADDR(info->id_VolumeNode))
  881.                     BtoCStr(buf,dl->dl_Name,100L);
  882.  
  883.                 switch(info->id_DiskState) {
  884.                     case ID_WRITE_PROTECTED: state="Read Only "; break;
  885.                     case ID_VALIDATED:       state="Read/Write"; break;
  886.                     case ID_VALIDATING:      state="Validating"; break;
  887.                     default:                 state="Unknown   "; break;
  888.                 }
  889.  
  890. #if 0
  891.                 size   = (info->id_NumBlocks + 2) * info->id_BytesPerBlock;
  892. #endif
  893.                 size   = info->id_NumBlocks * info->id_BytesPerBlock;
  894.                 freebl = info->id_NumBlocks - info->id_NumBlocksUsed;
  895.                 free   = freebl * info->id_BytesPerBlock;
  896.                 blocks = info->id_NumBlocks;
  897. #if 0
  898.                 printf("percents: %s... %ld, %ld, %ld, %ld, %ld\n",name,
  899.                     ((info->id_NumBlocksUsed+2) * 100)/blocks,
  900.                     (info->id_NumBlocksUsed * 100)/(blocks+2),
  901.                     (((info->id_NumBlocksUsed * 1000)/blocks)+5)/10,
  902.                     ((((info->id_NumBlocksUsed+2) * 1000)/blocks)+5)/10,
  903.                     (((info->id_NumBlocksUsed * 1000)/(blocks+2))+5)/10
  904.                 );
  905. #endif
  906.  
  907.                 if (mode==0 && options&2) {
  908.                     fmt="%-7s%6s%6d %6s %6s %6s %3d%%%4d  %10s %s\n";
  909.                     sprintf(infobuf,fmt,
  910.                         name,
  911.                         itok( size ),
  912.                         info->id_BytesPerBlock,
  913.                         type,
  914.                         itok( info->id_NumBlocksUsed*info->id_BytesPerBlock ),
  915.                         itok( free ),
  916.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  917. #if 0
  918.                         (blocks) ? ((info->id_NumBlocksUsed * 1000)/blocks + 5) / 10 : 0,
  919. #endif
  920.                         info->id_NumSoftErrors,
  921.                         state,
  922.                         buf);
  923.                 }
  924.                 else if (mode<=1) {
  925.                     if (mode==0) fmt="%-7s%6s%6d%7d%7d %6s%4d%%%4d  %s %s\n";
  926.                     sprintf(infobuf,fmt,
  927.                         name,
  928.                         itok( size ),
  929.                         info->id_BytesPerBlock,
  930.                         info->id_NumBlocksUsed,
  931.                         freebl,
  932.                         itok( free ),
  933.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  934.                         info->id_NumSoftErrors,
  935.                         state,
  936.                         buf);
  937.                 }
  938.                 else if (mode==2) sprintf(infobuf,"%d",free);
  939.                 else if (mode==3) sprintf(infobuf,"%d",freebl);
  940.                 else if (mode==4) sprintf(infobuf,"%s",itok(free));
  941.                 else if (mode==5) sprintf(infobuf,"%s:",buf);
  942.             }
  943.         }
  944.         else
  945.             pError(name);
  946.         FreeDeviceProc(devproc);
  947.     }
  948.  
  949. #if 0
  950.     else {
  951.         if (mode==1) {
  952.             struct MsgPort *devtask;
  953.             sprintf(infobuf,"%s\240No disk present\n",name);
  954.             if (devtask=(struct MsgPort *)DeviceProc(name)) {
  955.                 struct InfoData *infodata;
  956.                 infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  957.                 if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  958.                     switch (infodata->id_DiskType) {
  959.                     case ID_UNREADABLE_DISK:
  960.                         sprintf(infobuf,"%s\240Unreadable disk\n",name);
  961.                         break;
  962.                     case ID_NOT_REALLY_DOS:
  963.                         sprintf(infobuf,"%s\240Not a DOS disk\n",name);
  964.                         break;
  965.                     case ID_KICKSTART_DISK:
  966.                         sprintf(infobuf,"%s\240Kickstart disk\n",name);
  967.                         break;
  968.                     case (0x42555359L):  /* 'BUSY' */
  969.                         sprintf(infobuf,"%s\240Busy\n",name);
  970.                         break;
  971.                     case ID_NO_DISK_PRESENT:
  972.                     default:
  973.                         sprintf(infobuf,"%s\240No disk present\n",name);
  974.                         break;
  975.                     }
  976.                 }
  977.                 FreeMem(infodata,sizeof(struct InfoData));
  978.             }
  979.         }
  980.         else if (mode==0) {
  981.             if (options&1) {
  982.                 sprintf(infobuf,"");
  983.             }
  984.             else {
  985.                 struct MsgPort *devtask;
  986.                 sprintf(infobuf,"%-7s No disk present\n",name);
  987.                 if (devtask=(struct MsgPort *)DeviceProc(name)) {
  988.                     struct InfoData *infodata;
  989.                     infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  990.                     if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  991.                         switch (infodata->id_DiskType) {
  992.                         case ID_UNREADABLE_DISK:
  993.                             sprintf(infobuf,"%-7s Unreadable disk\n",name);
  994.                             break;
  995.                         case ID_NOT_REALLY_DOS:
  996.                             sprintf(infobuf,"%-7s Not a DOS disk\n",name);
  997.                             break;
  998.                         case ID_KICKSTART_DISK:
  999.                             sprintf(infobuf,"%-7s Kickstart disk\n",name);
  1000.                             break;
  1001.                         case (0x42555359L):  /* 'BUSY' */
  1002.                             sprintf(infobuf,"%-7s Disk is busy\n",name);
  1003.                             break;
  1004.                             case ID_NO_DISK_PRESENT:
  1005.                         default:
  1006.                             sprintf(infobuf,"%-7s No disk present\n",name);
  1007.                             break;
  1008.                         }
  1009.                     }
  1010.                     FreeMem(infodata,sizeof(struct InfoData));
  1011.                 }
  1012.             }
  1013.         }
  1014.         else if (mode==5) sprintf(infobuf,"");
  1015.         else              sprintf(infobuf,"0");
  1016.     }
  1017. #endif
  1018.  
  1019.     if (mode==0) printf("%s",infobuf);
  1020.  
  1021.     FreeMem(info,sizeof(struct InfoData));
  1022.     Myprocess->pr_WindowPtr = o_noreq ? (APTR) -1L : 0L/*Mywindow*/;
  1023.  
  1024.     return infobuf;
  1025. }
  1026.  
  1027.  
  1028. /* things shared with display_file */
  1029.  
  1030. #define DIR_SHORT 0x1
  1031. #define DIR_FILES 0x2
  1032. #define DIR_DIRS  0x4
  1033. #define DIR_NOCOL 0x8
  1034. #define DIR_NAMES 0x10
  1035. #define DIR_HIDE  0x20
  1036. #define DIR_LEN   0x40
  1037. #define DIR_TIME  0x80
  1038. #define DIR_BACK  0x100
  1039. #define DIR_UNIQ  0x200
  1040. #define DIR_IDENT 0x400
  1041. #define DIR_CLASS 0x800
  1042. #define DIR_QUIET 0x1000
  1043. #define DIR_AGE   0x2000
  1044. #define DIR_VIEW  0x4000
  1045. #define DIR_NOTE  0x8000
  1046. #define DIR_PATH  0x10000
  1047. #define DIR_LFORM 0x20000
  1048. #define DIR_BOT   0x40000
  1049. #define DIR_TOP   0x80000
  1050. #define DIR_LINK  0x100000
  1051.  
  1052. static char *lastpath = NULL;
  1053. static int filecount, dircount, col, colw, wwidth;
  1054. static long bytes, blocks;
  1055.  
  1056. /* the args passed to do_dir will never be expanded */
  1057.  
  1058. extern expand_err;
  1059. extern int w_width;
  1060.  
  1061. static struct DateStamp Stamp;
  1062. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  1063.  
  1064. int
  1065. do_dir( void )
  1066. {
  1067.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  1068.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=IsInteractive(Output());
  1069.     char linebuf[1024];
  1070.     char *fmtstr;
  1071.     int (*func)(), ac1, ac2, factor=0;
  1072.  
  1073.     LineBuf=LinePos=linebuf;
  1074.     LastWasDir=NoTitles=0;
  1075.     colw = -1;
  1076.  
  1077.     LFormat=_LFormat;
  1078.  
  1079.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  1080.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  1081.  
  1082.     DateStamp( &Stamp );
  1083.  
  1084.     col = filecount = dircount = bytes = blocks = 0L;
  1085.     if (lastpath) free(lastpath);
  1086.     lastpath=NULL;
  1087.  
  1088.     wwidth=77;
  1089.     if( inter )
  1090.         wwidth=w_width;
  1091.  
  1092.     if( options&DIR_SHORT )
  1093.         strcpy(LFormat," %-18n%19m");
  1094.     else if( options&DIR_PATH )
  1095.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  1096.     else {
  1097.         if ( options&DIR_NOTE )
  1098.             strcpy(LFormat,"  %-30n %o");
  1099.         else if ( options&DIR_LINK )
  1100.             strcpy(LFormat,"  %-30n %L");
  1101.         else {
  1102. #if 1
  1103.             strcpy(LFormat,"  ");
  1104. #else
  1105.             strcpy(LFormat,"  %-30n ");
  1106. #endif
  1107.             if( options&DIR_HIDE )
  1108.                 strcat(LFormat, "%e");
  1109.             strcat(LFormat,"%c%I%f ");
  1110.             if( options&DIR_VIEW )
  1111.                 strcat(LFormat,"%10v  ");
  1112.             else
  1113.                 strcat(LFormat,"%8s  ");
  1114. #if 0
  1115.             if( !(options&DIR_QUIET) )
  1116.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  1117. #endif
  1118.             if( options&DIR_IDENT )
  1119.                 strcat(LFormat,"%-10k");
  1120.             else if( options&DIR_AGE )
  1121.                 strcat(LFormat,"%a");
  1122.             else
  1123.                 strcat(LFormat,"%d %t");
  1124. #if 1
  1125.             strcat(LFormat,"  %N");
  1126. #endif
  1127.         }
  1128.     }
  1129.  
  1130. #if 1
  1131.     /* if option -z, use variable _dirformat or first argument (if no _dirformat) */
  1132.  
  1133.     if ( options&DIR_LFORM ) {
  1134.         if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  1135.             strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  1136.             LFormat[79]=0;
  1137.         }
  1138.         else if (ac>1)
  1139.             LFormat=av[i++];
  1140.         else {
  1141.             show_usage(NULL);
  1142.             return 20;
  1143.         }
  1144.     }
  1145. #else
  1146.     /* variable _dirformat always used, can be overwritten by -z fmt */
  1147.  
  1148.     if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  1149.         strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  1150.         LFormat[79]=0;
  1151.     }
  1152.  
  1153.     if ( options&DIR_LFORM ) {
  1154.         if (ac>1)
  1155.             LFormat=av[i++];
  1156.         else {
  1157.             show_usage(NULL);
  1158.             return 20;
  1159.         }
  1160.     }
  1161. #endif
  1162.  
  1163.     if( ac == i) ++nump, av[i]="";
  1164.     if( options&DIR_UNIQ) {
  1165.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  1166.         i=0, nump=3;
  1167.     }
  1168.  
  1169.     prepscroll(0);
  1170.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  1171.         if( options&DIR_UNIQ ) {
  1172.             switch( i ) {
  1173.                 case 0: av1=expand( av[ac-2], &ac1 );
  1174.                         av2=expand( av[ac-1], &ac2 );
  1175.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  1176.                         break;
  1177.                 case 1: printf("\nCommon files\n");
  1178.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  1179.                         break;
  1180.                 case 2: printf("\n");
  1181.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  1182.                         break;
  1183.             }
  1184.             col = filecount = dircount = bytes = blocks = 0L;
  1185.             if (lastpath) free(lastpath);
  1186.             lastpath=NULL;
  1187.  
  1188.         /* AMK: enhanced handling of non-matching patterns */
  1189.         } else if (!(eav = expand(av[i], &eac))) {
  1190.             if (IoError) {
  1191.                 ierror(av[i],IoError);
  1192.                 retcode=5;
  1193.             }
  1194. #if 0
  1195.             else {
  1196.                 if (strlen(av[i])>0)
  1197.                     fprintf(stderr,"%s: No match.\n",av[i]);
  1198.             }
  1199. #endif
  1200.             continue;
  1201.         }
  1202.  
  1203.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  1204.         func=cmp;
  1205.         if( options & DIR_TIME) func   = datecmp_csh;
  1206.         if( options & DIR_LEN ) func   = sizecmp;
  1207.         if( options & DIR_CLASS)func   = classcmp;
  1208.         if( options & DIR_BOT ) factor = -99999999;
  1209.         if( options & DIR_TOP ) factor = 99999999;
  1210.         DirQuickSort(eav, eac, func, reverse, factor);
  1211.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  1212.             if( options & DIR_HIDE ) {
  1213.                 char *b=FilePart(eav[c]);
  1214.                 int  l=strlen(b)-5;
  1215.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  1216.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  1217.                     continue;
  1218.             }
  1219.             if (options & DIR_NAMES) {
  1220.                 FILEINFO *info = (FILEINFO *)eav[c] - 1;
  1221.                 if(options&(info->size<0 ? DIR_DIRS: DIR_FILES))
  1222.                     puts(eav[c]);
  1223.             } else
  1224.                 display_file(eav[c]);
  1225.         }
  1226.  
  1227.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1228.  
  1229.         if( LastWasDir )
  1230.             printf(o_lolite), LastWasDir=0;
  1231.  
  1232.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  1233.             blocks += filecount-dircount; /* account for dir blocks */
  1234.             quickscroll();
  1235.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  1236.                 blocks, itoa(bytes), filecount);
  1237.         }
  1238.         if( options&DIR_UNIQ )
  1239.             free(eav);
  1240.         else
  1241.             free_expand (eav);
  1242.     }
  1243.     if (lastpath) free(lastpath);
  1244.     lastpath=NULL;
  1245.  
  1246.     if( options&DIR_UNIQ )
  1247.         free_expand( av1 ), free_expand( av2 );
  1248.  
  1249.     return retcode;
  1250. }
  1251.  
  1252. static int MultiCol = -1;
  1253.  
  1254. static char
  1255. pathcomp( char *s1, char *s2 )
  1256. {
  1257.     char ret, *t, c;
  1258.  
  1259.     t=FilePart( s2 ); c = *t; *t=0;
  1260.     ret=stricmp( s1, s2 );
  1261.     *t=c;
  1262.     return ret;
  1263. }
  1264.  
  1265. static void
  1266. display_file( char *filestr )
  1267. {
  1268.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  1269.     int isadir, len, collen;
  1270.     char sc, *base, buf[1024], *hilite;
  1271.     FILEINFO *info;
  1272.     BPTR thislock;
  1273.  
  1274.     base=FilePart(filestr);
  1275.     sc = *base;
  1276.     *base = 0;
  1277.     /* if (thislock==NULL) return; */
  1278.     if( !NoTitles ) {
  1279.         if( !lastpath || pathcomp( filestr, lastpath)) {
  1280.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  1281.                 return;
  1282.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1283.             quickscroll();
  1284.             if (!NameFromLock(thislock, buf, 256)) {
  1285.                 fprintf(stderr,"csh.display_file: NameFromLock() failed\n");
  1286.                 strcpy(buf,filestr);
  1287.             }
  1288.             if( LastWasDir )
  1289.                 printf(o_lolite), LastWasDir=0;
  1290.             printf("Directory of %s\n", buf );
  1291.             /* Info( thislock, id ); */
  1292.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  1293.             /* FreeMem( id, sizeof(struct InfoData)); */
  1294.             lastpath = salloc(256);
  1295.             strcpy(lastpath,filestr);
  1296.             /*lastpath=filestr;*/
  1297.             UnLock(thislock);
  1298.         }
  1299.     }
  1300.     *base    = sc;
  1301.  
  1302.     info   = (FILEINFO *)filestr - 1;
  1303.     isadir = info->size<0;
  1304.  
  1305.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  1306.         return;
  1307.  
  1308.     hilite="";
  1309.     if (isadir!=LastWasDir && !(options & DIR_NOCOL))
  1310.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  1311.  
  1312.     lformat(LFormat, buf, info);
  1313.  
  1314.     if( MultiCol == -1 ) {
  1315.         quickscroll();
  1316.         printf("%s%s",hilite,buf);
  1317.     } else {
  1318.         len=strlen(buf);
  1319.         if( col+len>wwidth ) {
  1320.             quickscroll();
  1321.             puts(LineBuf);
  1322.             LinePos=LineBuf; col=0;
  1323.         }
  1324.         if( MultiCol )
  1325.             colw=MultiCol;
  1326.         else if( colw == -1 )
  1327.             colw=len;
  1328.         collen= (len+colw-1)-(len+colw-1)%colw;
  1329.         col+=collen;
  1330.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  1331.     }
  1332.  
  1333.     if(info->size>0)
  1334.         bytes  += info->size;
  1335.     blocks += info->blocks;
  1336.     filecount++;
  1337. }
  1338.  
  1339. static char linebuf[1024];
  1340. static long dlen, dblocks;
  1341.  
  1342. static int
  1343. count( long mask, char *s, char *path )
  1344. {
  1345.     FIB *fib=(FIB*)s-1;
  1346.     dlen+=fib->fib_Size;
  1347.     dblocks+=fib->fib_NumBlocks+1;
  1348.     return 0;
  1349. }
  1350.  
  1351.  
  1352. /* code contribution by Carsten Heyl, modified by AMK */
  1353. void ReadSoftLink(char *path, char *buf, int buflen)
  1354. {
  1355.     BPTR MyLock;
  1356.     BPTR DevLock;
  1357.     LONG Err, l;
  1358.     UBYTE *bs;
  1359.     struct MsgPort *port;
  1360.  
  1361.     if (buflen>9)
  1362.         strcpy(buf,"<unknown>");
  1363.     else
  1364.         buf[0] = '\0';    /* just terminate buffer. alternative ? */
  1365.  
  1366.     if ( (l=strlen(path)) > 254 )
  1367.         return;
  1368.  
  1369.     if (!(bs=AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC)))
  1370.         return;
  1371.  
  1372.     bs[255] = '\0';
  1373.  
  1374.     /* build BCPL string */
  1375.     bs[0] = l;
  1376.     memcpy(&bs[1], path, l+1);
  1377.  
  1378.     /* GetDeviceProc or DeviceProc? */
  1379.     if (!(port = DeviceProc(path))) {
  1380.         FreeMem(bs,256);
  1381.         return;
  1382.     }
  1383.  
  1384.     DevLock = (BPTR)IoErr();
  1385.  
  1386.     MyLock = DoPkt(port,ACTION_LOCATE_OBJECT,DevLock,MKBADDR(bs),
  1387.                 ACCESS_READ,NULL,NULL);
  1388.     Err = IoErr();
  1389.  
  1390.     if (!MyLock && (Err==ERROR_IS_SOFT_LINK)) {
  1391. #if 0
  1392.         ReadLink(port,DevLock,(UBYTE *)path,(UBYTE *)buf,buflen);
  1393. #else
  1394.         DoPkt(port,ACTION_READ_LINK,DevLock,(LONG)path,(LONG)buf,buflen,NULL);
  1395. #endif
  1396.     }
  1397.  
  1398.     if (MyLock) UnLock(MyLock);
  1399.     FreeMem(bs,256);
  1400. }
  1401.  
  1402.  
  1403. void
  1404. lformat( char *s, char *d, FILEINFO *info )
  1405. {
  1406.     long mi=0;
  1407.     char buf[1024], *w, *class;
  1408.     DPTR *dp;
  1409.     int stat, i, form, sign, cut, size=info->size;
  1410.     char *(*func)(int num);
  1411.  
  1412.     MultiCol = -1;
  1413.     while( *s ) {
  1414.         if( *s!='%' ) { *d++ = *s++; continue; }
  1415.         sign=1; form=0; cut=0; s++;
  1416.         if( *s=='-' ) s++, sign = -1;
  1417.         if( *s=='.' ) s++, cut=1;
  1418.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  1419.         w=buf; w[0]=0; w[1]=0;
  1420.         switch( *s ) {
  1421.         case 'p': strcpy(w,(char *)(info+1));             break;
  1422.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  1423.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  1424.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  1425.         case 'r':
  1426.         case 'u':
  1427.             if( *s=='r' ) func=itoa; else func=itok;
  1428.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  1429.             break;
  1430.         case 'n':
  1431.         case 'q':
  1432.             strcpy(w,FilePart((char *)(info+1)));
  1433.             if( *s=='q' && size<0 ) strcat(w,"/");
  1434.             break;
  1435.         case 'l':
  1436.             if( info->flags & INFO_COMMENT ) *w='\n';
  1437.             break;
  1438.         case 'c':
  1439.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  1440.             break;
  1441.         case 'e':
  1442.             *w= info->flags & INFO_INFO ? 'i' : '-';
  1443.             break;
  1444.         case '+':
  1445.             *w= info->flags & INFO_INFO ? '+' : ' ';
  1446.             break;
  1447.         case 'L':
  1448.         case 'N':
  1449.             if (*s=='N')
  1450.                 strcpy(w,FilePart((char *)(info+1)));
  1451.             else
  1452.                 strcpy(w,"");
  1453.             if (info->type==ST_SOFTLINK) {
  1454.                 strcat(w," -> ");
  1455.                 ReadSoftLink((char *)(info+1),w+strlen(w),256);
  1456.             }
  1457.             else if (info->type==ST_LINKDIR || info->type==ST_LINKFILE) {
  1458.                 BPTR lock;
  1459.                 if (lock=Lock((char *)(info+1),ACCESS_READ)) {
  1460.                     strcat(w," -> ");
  1461.                     if (!NameFromLock(lock,w+strlen(w),256)) {
  1462.                         fprintf(stderr,"csh.lformat: NameFromLock() failed\n");
  1463.                         strcpy(w+strlen(w),(char *)(info+1));
  1464.                     }
  1465.                     UnLock(lock);
  1466.                 }
  1467.             }
  1468.             break;
  1469.         case 'I':
  1470.             switch (info->type) {
  1471.                 case ST_SOFTLINK:
  1472.                     *w='S';
  1473.                     break;
  1474.                 case ST_LINKDIR:
  1475.                 case ST_LINKFILE:
  1476.                     *w='H';
  1477.                     break;
  1478.                 case ST_PIPEFILE:
  1479.                     *w='P';
  1480.                     break;
  1481.                 default:
  1482.                     *w='-';
  1483.                     break;
  1484.             }
  1485.             break;
  1486.         case 'f': /* standard flags */
  1487.             for (i=7; i>=0; i--)
  1488.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  1489.             *w=0;
  1490.             break;
  1491.         case 'F': /* group/other flags */
  1492.             for (i=3; i>=0; i--)
  1493.                 *w++ = (info->flags^15) & (1L<<(i+8)) ? "rwed"[3-i] : '-';
  1494.             *w++ = ' ';
  1495.             for (i=3; i>=0; i--)
  1496.                 *w++ = (info->flags^15) & (1L<<(i+12)) ? "rwed"[3-i] : '-';
  1497.             *w=0;
  1498.             break;
  1499.         case 'U': /* user-id */
  1500.             sprintf(w,"%d",info->uid);
  1501.             break;
  1502.         case 'G': /* group-id */
  1503.             sprintf(w,"%d",info->gid);
  1504.             break;
  1505.         case 'a':
  1506.             if( Stamp.ds_Days!=0 ) {
  1507.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  1508.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  1509.             }
  1510.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  1511.                       mi/1440,mi/60%60,mi%60);
  1512.             break;
  1513.         case 'o':
  1514.             if( dp=dopen( (char *)(info+1), &stat )) {
  1515.                 strcpy( w, dp->fib->fib_Comment );
  1516.                 dclose( dp );
  1517.             }
  1518.             break;
  1519.         case 'v':
  1520.         case 'w':
  1521.             if( *s=='v' ) func=itoa; else func=itok;
  1522.             dlen=dblocks=0;
  1523.             if( size<0 ) {
  1524.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  1525.                             (char *)(info+1),count);
  1526.                 strcpy( w, (*func)(dlen));
  1527.                 info->size=size=dlen; info->blocks=dblocks;
  1528.             } else
  1529.                 strcpy( w, (*func)(size));
  1530.             break;
  1531.         case 'k':
  1532.             if( *info->class!=1 )
  1533.                 strcpy(w,info->class);
  1534.             else if( class=getclass((char *)(info+1)))
  1535.                 if( w=index(strncpy(w,class,50),0xA0) )
  1536.                     *w=0;
  1537.             break;
  1538.         case 'x':
  1539.         case 'd':
  1540.             sprintf(w,"%9s",dates(&info->date,*s=='x'));
  1541. #if 0
  1542. /*
  1543.  *  the sprint() already relies on the fact that the date string
  1544.  *  is exactly 9 characters long, so we don't need to search for
  1545.  *  spaces or do other fancy stuff ;-)
  1546.  */
  1547.             /* strip off after first space */
  1548.             if (t=strchr(w,' '))
  1549.                 *t='\0';
  1550. #endif
  1551.             break;
  1552.         case 't':
  1553.             sprintf(w,"%8s", next_word(dates(&info->date,0)));
  1554.             break;
  1555.         case 'm': MultiCol = form; form = 0;    break;
  1556.         case '%': *w = *++s;                    break;
  1557.         case  0 : *w = '%';                     break;
  1558.         default : *w = '%';  *w++ = *s; *w = 0; break;
  1559.         }
  1560.         if( cut ) buf[form]=0;
  1561.         *d=0; s++;
  1562.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  1563.     }
  1564.     if( MultiCol == -1 ) { *d++='\n'; }
  1565.     *d=0;
  1566. }
  1567.  
  1568.  
  1569.  
  1570. extern BOOL nologout;    /* defined in main.c */
  1571.  
  1572. int
  1573. do_quit( void )
  1574. {
  1575.     if (Src_stack) {
  1576.         Quit = 1;
  1577.         return(do_return());
  1578.     }
  1579.     if (!nologout) {
  1580.         if( exists("S:.logout"))
  1581.             execute("source S:.logout");
  1582.     }
  1583.     main_exit(0);
  1584.     return 0;
  1585. }
  1586.  
  1587. int
  1588. do_echo( void )
  1589. {
  1590.     char *args=compile_av(av,1,ac,' ',0);
  1591.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  1592.     free(args);
  1593.     return 0;
  1594. }
  1595.  
  1596.  
  1597. static int
  1598. breakcheckd(void)
  1599. {
  1600.     long sigs = SetSignal(0L,0L);
  1601.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_D);
  1602.     if (ret)
  1603.         fprintf(stderr,"^D\n");
  1604.     return ret;
  1605. }
  1606.  
  1607. static int
  1608. breakchecke(void)
  1609. {
  1610.     long sigs = SetSignal(0L,0L);
  1611.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_E);
  1612.     if (ret)
  1613.         fprintf(stderr,"^E\n");
  1614.     return ret;
  1615. }
  1616.  
  1617.  
  1618. /* gets a line from file, joining lines if they end in '\' */
  1619.  
  1620. #define MAXLINE 512
  1621.  
  1622. static int
  1623. srcgets(char **buf, int *buflen, FILE *file)
  1624. {
  1625.     char *bufptr = *buf, *p, *new, concat=0, cont;
  1626.     int   totlen=0, len;
  1627.  
  1628.     do {
  1629.         if( totlen+MAXLINE > *buflen ) {
  1630.             new=salloc(*buflen *= 2);
  1631.             memcpy( new, *buf, 1+bufptr-*buf );
  1632.             bufptr+= new-*buf;
  1633.             free(*buf);
  1634.             *buf=new;
  1635.         }
  1636.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  1637.             if( concat )
  1638.                 fprintf(stderr,"Source: missing '}'\n");
  1639.             else if (bufptr != *buf)
  1640.                 fprintf(stderr,"Source: file ends in '\\'\n");
  1641.             return -1;
  1642.         }
  1643.         len= strlen( bufptr );
  1644.         totlen+= len;
  1645.  
  1646.         cont=0;
  1647.  
  1648.         p=bufptr+len-1;
  1649.         if(  p>=bufptr && *p=='\n') *p--=0;
  1650.         if(  p< bufptr   ) ;
  1651.         else if( *p=='\\') *p--=0, cont=1;
  1652.         else if( *p=='{' ) concat++;
  1653.         else if( *p=='}' ) {
  1654.             if( concat>0 ) {
  1655.                 concat--;
  1656.                 if( concat ) *++p='\n';
  1657.             }
  1658.         } else if( concat ) *++p='\n';
  1659.         bufptr = ++p;
  1660.     } while( cont || concat );
  1661.     *bufptr=0;
  1662.     return totlen;
  1663. }
  1664.  
  1665.  
  1666.  
  1667. int
  1668. do_source( char *str )
  1669. {
  1670.     FILE *fi;
  1671.     char *buf;
  1672.     ROOT *root;
  1673.     int  retcode, len, bufsize=512+MAXLINE;
  1674.     int j;
  1675.     char *ptr;
  1676.  
  1677.     if (Src_stack == MAXSRC) {
  1678.         ierror(NULL,217);
  1679.         return -1;
  1680.     }
  1681.  
  1682.     if ((fi = fopen (av[1], "r")) == 0)
  1683.         { pError(av[1]); return -1;    }
  1684.  
  1685.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  1686.     buf=salloc(bufsize);
  1687.  
  1688.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  1689.  
  1690.  
  1691.     /*
  1692.      * now create a bunch of positional parameters , $0, $1 etc
  1693.      */
  1694.     j = 0;
  1695.     ptr = next_word (str);
  1696.     while (*ptr) {
  1697.         char *var;
  1698.         char p[6];
  1699.         char npos[6];
  1700.  
  1701.         var = ptr;
  1702.         sprintf (p, "%d", j);
  1703.         /*
  1704.          * term var str
  1705.          */
  1706.         ptr = next_word (ptr);
  1707.  
  1708.         /* printf("%s\n" , ptr); */
  1709.  
  1710.         if (*ptr)
  1711.             *(ptr - 1) = '\0';
  1712.  
  1713.         set_var (LEVEL_SET | LEVEL_LOCAL, p, var);
  1714.         /*
  1715.          * now set up what should be $# ( number of positionals )
  1716.          */
  1717. #if 0
  1718.         sprintf (p, "_N");    /* should be "#" but csh barfs :( */
  1719. #endif
  1720.         sprintf (p, "#");    /* hackin' */
  1721.         sprintf (npos, "%d", j++);
  1722.         set_var (LEVEL_SET | LEVEL_LOCAL, p, npos);
  1723.     }
  1724.  
  1725.  
  1726.     Src_pos  [Src_stack] = 0;
  1727.     Src_abort[Src_stack] = 0;
  1728.     Src_base [Src_stack] = fi;
  1729.     Src_if[Src_stack]=If_stack;
  1730.     ++Src_stack;
  1731.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  1732.         Src_pos[Src_stack-1] += len;
  1733.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  1734.             if( Verbose&VERBOSE_HILITE )
  1735.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  1736.             else
  1737.                 fprintf(stderr,")%s\n",buf);
  1738.         retcode=execute(buf);
  1739.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  1740.             break;
  1741.         retcode=0;
  1742.     }
  1743.     --Src_stack;
  1744.     if( If_stack>Src_if[Src_stack] )
  1745.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  1746.  
  1747.     if (forward_goto) ierror(NULL,501);
  1748.     forward_goto = 0;
  1749.     unset_level(LEVEL_LABEL+ Src_stack);
  1750.     unset_var(LEVEL_SET, v_gotofwd);
  1751.     unset_var(LEVEL_SET, v_passed);
  1752.     fclose (fi);
  1753.  
  1754.     pop_locals();
  1755.     free(buf);
  1756.     free(root);
  1757.  
  1758.     return retcode;
  1759. }
  1760.  
  1761. /* set process cwd name and $_cwd, if str != NULL also print it. */
  1762.  
  1763. void
  1764. set_cwd(void)
  1765. {
  1766.     char pwd[256];
  1767.  
  1768.     if (!NameFromLock(Myprocess->pr_CurrentDir, pwd, 254)) {
  1769.         fprintf(stderr,"csh.set_cwd: NameFromLock() failed\n");
  1770.         strcpy(pwd,"<unknown>");
  1771.     }
  1772.     set_var(LEVEL_SET, v_cwd, pwd);
  1773.     /* put the current dir name in our CLI task structure */
  1774.     CtoBStr(pwd, Mycli->cli_SetName, 254);
  1775. }
  1776.  
  1777. int
  1778. do_pwd( void )
  1779. {
  1780.     set_cwd();
  1781.     puts( get_var( LEVEL_SET, v_cwd ));
  1782.     return 0;
  1783. }
  1784.  
  1785.  
  1786. /*
  1787.  * CD
  1788.  *
  1789.  * CD(str, 0)      -do CD operation.
  1790.  *
  1791.  */
  1792.  
  1793. extern int qcd_flag;
  1794.  
  1795. static char lastqcd[256];
  1796. static FILE *qcdfile;
  1797. static int  NumDirs;
  1798.  
  1799. static int
  1800. countfunc( long mask, char *file, char *fullpath )
  1801. {
  1802.     fprintf( qcdfile, "%s\n", fullpath );
  1803.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  1804.     fflush ( stdout );
  1805.     return 0;
  1806. }
  1807.  
  1808. int
  1809. do_cd(void)
  1810. {
  1811.     BPTR oldlock, filelock;
  1812.     char buf[256], *old, *str=av[1];
  1813.     int  i=1, repeat;
  1814.  
  1815.     if( options & 1 ) {
  1816.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  1817.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  1818.             { fprintf(stderr,"Can't open output\n"); return 20; }
  1819.         for( ; i<ac && !dobreak(); i++ ) {
  1820.             NumDirs=0;
  1821.             printf("%s\n",av[i]);
  1822.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  1823.             printf("\n");
  1824.         }
  1825.         fclose(qcdfile);
  1826.         return 0;
  1827.     }
  1828.  
  1829.     if ( !str || !(*str) ) {    /* old "!*str" causes enforcer hit! */
  1830.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  1831.         return 0;
  1832.     }
  1833.  
  1834.     if (filelock=Lock(str,ACCESS_READ)) {
  1835.         lastqcd[0]=0;
  1836.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  1837.     } else {
  1838.         repeat= !strncmp( lastqcd, str, 255 );
  1839.         strncpy( lastqcd, str, 255 );
  1840.  
  1841.         if( !quick_cd( buf, av[i], repeat) )
  1842.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  1843.         if (!(filelock=Lock(buf,ACCESS_READ)))
  1844.             { pError(buf); return 20; }
  1845.     }
  1846.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  1847.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  1848.         old="";
  1849.     set_var(LEVEL_SET, v_lcd, old);
  1850.     set_cwd();
  1851.  
  1852.     return 0;
  1853. }
  1854.  
  1855. char *
  1856. quick_cd( char *buf, char *name, int repeat )
  1857. {
  1858.     if( !o_csh_qcd || !exists(o_csh_qcd))
  1859.         return NULL;
  1860.     qcd_flag=repeat ? 2 : 1;
  1861.     strcpy(buf,name);
  1862.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  1863.         return NULL;
  1864.     return buf;
  1865. }
  1866.  
  1867.  
  1868. /* AMK: mkdir now builds path to destination directory if neccessary */
  1869. int
  1870. do_mkdir( void )
  1871. {
  1872.     int i;
  1873.     BPTR lock;
  1874.     char *p,c;
  1875.  
  1876.     for (i=1; i<ac; ++i) {
  1877.  
  1878.         /* Are there any sub-directories to build? */
  1879.         if( options&1 && (p=strchr(av[i],'/'))) {
  1880.             do {
  1881.                 c = *p;
  1882.                 *p = '\0';
  1883.                 if (lock=CreateDir(av[i]))
  1884.                     UnLock(lock);
  1885.                 *p = c;
  1886.             } while(p=strchr(++p,'/'));
  1887.         }
  1888.  
  1889.         /* allow trailing slash */
  1890.         if (lastch(av[i]) == '/' )
  1891.             av[i][strlen(av[i])-1] = '\0';
  1892.  
  1893.         /* Okay, sub-directories should exist, now try normal mkdir. */
  1894.  
  1895.         if (lock=CreateDir(av[i]))
  1896.             UnLock(lock);
  1897.         else
  1898.             pError(av[i]);
  1899.  
  1900.     }
  1901.  
  1902.     return 0;
  1903. }
  1904.  
  1905. int
  1906. do_mv( void )
  1907. {
  1908.     char *dest, buf[256];
  1909.     int dirflag, i, len;
  1910.  
  1911.     dirflag=isdir(dest=av[--ac]);
  1912.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  1913.     for (i=1; i<ac; ++i) {
  1914.         strcpy(buf, dest);
  1915.  
  1916.         /* source: remove trailing slash */
  1917.         if ((len=strlen(av[i]))>1 && av[i][len-1]=='/' && av[i][len-2]!=':' && av[i][len-2]!='/')
  1918.             av[i][len-1] = '\0';
  1919.  
  1920.         /* destination: remove trailing slash */
  1921.         if ((len=strlen(buf))>1 && buf[len-1]=='/' && buf[len-2]!=':' && buf[len-2]!='/')
  1922.             buf[len-1] = '\0';
  1923.  
  1924.         if (dirflag && stricmp(av[i],buf))
  1925.              AddPart(buf, FilePart(av[i]), 255L);
  1926.  
  1927.         if (Rename(av[i], buf)==0) {
  1928.             pError(av[i]);
  1929.             if (!(options&1))
  1930.                 return -1;
  1931.         }
  1932.         else {
  1933.             clear_archive_bit( buf );
  1934.             if (options&2) {
  1935.                 /*printf("Renaming %s as %s\n",av[i],buf);*/
  1936.                 printf(" %s...%s\n",av[i],dirflag?"moved":"renamed");
  1937.             }
  1938.         }
  1939.     }
  1940.     return 0;
  1941. }
  1942.  
  1943. static char *searchstring;
  1944. static char docr;
  1945.  
  1946. #if 0
  1947. int
  1948. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1949. {
  1950.     int  i;
  1951.     long mask= SCAN_FILE;
  1952.  
  1953.     if( options&1 )
  1954.         mask |= SCAN_RECURSE;
  1955.     if( dirsflag )
  1956.         mask |= SCAN_DIR;
  1957.  
  1958.     for ( i=1; i<ac && !dobreak(); ++i)
  1959.         if (isdir(av[i])) {
  1960.             if (options & 1)
  1961.                 newrecurse(mask, av[i], action);
  1962.             if (dirsflag)
  1963.                 (*action)(SCAN_DIR,av[i],av[i]);
  1964.         } else
  1965.             (*action)(SCAN_FILE,av[i],av[i]);
  1966.     if(docr) printf("\n"),docr=0;
  1967.     dobreak();
  1968.     return 0;
  1969. }
  1970. #endif
  1971.  
  1972. /* this is all_args() but with a user definable range from n to m */
  1973. int
  1974. all_args_n2m( int (*action)FUNCARG(long,char*,char*), int dirsflag, int aa_from, int aa_to )
  1975. {
  1976.     int  i;
  1977.     long mask= SCAN_FILE;
  1978.  
  1979.     if( options&1 )
  1980.         mask |= SCAN_RECURSE;
  1981.     if( dirsflag )
  1982.         mask |= SCAN_DIR;
  1983.  
  1984.     for ( i=aa_from; i<aa_to && !dobreak(); ++i)
  1985.         if (isdir(av[i])) {
  1986.             if (options & 1)
  1987.                 newrecurse(mask, av[i], action);
  1988.             if (dirsflag)
  1989.                 (*action)(SCAN_DIR,av[i],av[i]);
  1990.         } else
  1991.             (*action)(SCAN_FILE,av[i],av[i]);
  1992.     if(docr) printf("\n"),docr=0;
  1993.     dobreak();
  1994.     return 0;
  1995. }
  1996.  
  1997. int
  1998. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1999. {
  2000.     return( all_args_n2m(action,dirsflag,1,ac) );
  2001. }
  2002.  
  2003. #define SEARCH_REC   1
  2004. #define SEARCH_CASE  2
  2005. #define SEARCH_WILD  4
  2006. #define SEARCH_NUM   8
  2007. #define SEARCH_EXCL  16
  2008. #define SEARCH_QUIET 32
  2009. #define SEARCH_VERB  64
  2010. #define SEARCH_BIN   128
  2011. #define SEARCH_FILE  256
  2012. #define SEARCH_ABORT 512
  2013. #define SEARCH_LEFT  1024
  2014. #define SEARCH_ONLY  2048
  2015.  
  2016. /* added by amk, not yet implemented */
  2017. #define SEARCH_STYLE 4096    /* alternative style, inspired by GMD */
  2018. #define SEARCH_ONCE  8192    /* only show first pattern match per file */
  2019.  
  2020. static int abort_search;
  2021. static char lowbuf[256], file_name, file_cr;
  2022.  
  2023. static int
  2024. search_file( long mask, char *s, char *fullpath )
  2025. {
  2026.     PATTERN *pat;
  2027.     FILE *fi;
  2028.     char *p, *q;
  2029.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  2030.     char buf[256], searchit[120], first, left;
  2031.  
  2032.     if( abort_search )
  2033.         return 0;
  2034.  
  2035.     nocasedep=!(options & SEARCH_CASE);
  2036.     lctr= docr= file_name= file_cr= 0;
  2037.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  2038.         if( options & SEARCH_VERB )
  2039.             printf("Examining %s ...\n",fullpath);
  2040.         else
  2041.             printf("\015Examining %s ...\033[K",fullpath), docr=1;
  2042.         fflush( stdout );
  2043.     }
  2044.  
  2045.     strcpy(searchit,searchstring);
  2046.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  2047.     len=strlen(searchit);
  2048.     if (nocasedep) strupr(searchit);
  2049.     first = *searchit;
  2050.  
  2051.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  2052.                  options&SEARCH_BIN )
  2053.         if( quicksearch(s,nocasedep,searchit) )
  2054.             return 0;
  2055.  
  2056.     if( options&SEARCH_BIN )
  2057.         { fprintf(stderr,"Out of memory\n"); return 20; }
  2058.  
  2059.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE )))
  2060.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  2061.  
  2062.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  2063.     if (fi==NULL) { pError(s); return 20; }
  2064.  
  2065.     prepscroll(0);
  2066.  
  2067.     while (fgets(buf,256,fi) && !dobreak()) {
  2068.         lctr++; left=1;
  2069.         if (options & SEARCH_WILD)
  2070.             yesno=compare_ok(pat, p=buf);
  2071.         else {
  2072.             if (nocasedep) {
  2073.                 strcpy(lowbuf,buf);
  2074.                 strupr(lowbuf);
  2075.                 p=lowbuf;
  2076.             } else
  2077.                 p=buf;
  2078.             q=p;
  2079.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  2080.             yesno= (p!=NULL);
  2081.             left = --p - q;
  2082.         }
  2083.         if( yesno ^ excl )
  2084.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  2085.                 if( found(buf, lctr, 0, s, left ) )
  2086.                     break;
  2087.     }
  2088.     compare_free(pat);
  2089.     if (fi!=stdin) fclose (fi);
  2090.     if( file_cr ) printf("\n");
  2091.     return 0;
  2092. }
  2093.  
  2094. int qcd_flag, qcd_offs;
  2095.  
  2096. #define READCHUNK 60000
  2097.  
  2098. static int
  2099. quicksearch( char *name, int nocasedep, char *pattern )
  2100. {
  2101.     int i, ptrn=strlen(pattern);
  2102.     char ut[256], *buffer, *lend;
  2103.     char *uptab=ut, *get, c, *lpos, *lstart;
  2104.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  2105.     int sofar, got;
  2106.     BPTR fh;
  2107.  
  2108. #ifdef AZTEC_C
  2109.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  2110. #endif
  2111.  
  2112.     qcd_flag=0;
  2113.     if( !(fh=Open(name,MODE_OLDFILE))) {
  2114.         i=(long)IoErr(), docr=0;
  2115.         printf("\n");
  2116.         ierror(name,i);
  2117.         return 1;
  2118.     }
  2119.     len=filesize( name );
  2120.     buflen=len+3;
  2121.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  2122.     sofar=0;
  2123.     do {
  2124.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  2125.         sofar+=got;
  2126.     } while( got==READCHUNK );
  2127.     Close( fh);
  2128.     if( sofar != len ) {
  2129.         FreeMem( buffer, buflen );
  2130.         pError(pattern); return 1;
  2131.     }
  2132.     if(buffer[len-1]!='\n')
  2133.         buffer[len++]='\n';
  2134.  
  2135.     if( nocasedep )
  2136.         strupr( pattern );
  2137.  
  2138.     if( !qcd )
  2139.         prepscroll(0);
  2140.  
  2141.     for( i=0; i<256; i++ ) uptab[i]=i;
  2142.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  2143. retry:
  2144.     c = *pattern, buffer[len]=c, buffer[len+1]=c;
  2145.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  2146.     if( qcd==1 ) qcd_offs=0;
  2147.  
  2148.     lpos=lstart=buffer, lnum=1;
  2149.     for( ;; ) {
  2150.         do ; while( uptab[*get++]!=c );
  2151.         if( --get>=buffer + len )
  2152.             break;
  2153.         for( i=1; i<ptrn; i++ )
  2154.             if( uptab[get[i]]!=pattern[i] )
  2155.                 break;
  2156.         if( i==ptrn ) {
  2157.             for( ;lpos<get; lpos++ )
  2158.                 if( *lpos=='\n' )
  2159.                     lstart=lpos+1, lnum++;
  2160.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  2161.             if( qcd ) {
  2162.                 if( get[-1]==':' || get[-1]=='/' ||
  2163.                       lpos==lstart && lend[-1]==':' ) {
  2164.                     char *tmp;
  2165.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  2166.                     if( *tmp!='/' ) {
  2167.                         *lend=0;
  2168.                         strncpy(pattern,lstart,79);
  2169.                         qcd_offs=lend-buffer;
  2170.                         FreeMem( buffer, buflen );
  2171.                         return 2;
  2172.                     }
  2173.                 } else 
  2174.                     lend=lpos+1;
  2175.             } else {
  2176.                 *lend=0;
  2177.                 if(!(options&SEARCH_ONLY) ||
  2178.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  2179.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  2180.                         break;
  2181.                 *lend='\n';
  2182.             }
  2183.             get=lend+1;
  2184.         } else
  2185.             get++;
  2186.     }
  2187.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  2188.     if( file_cr ) { printf("\n"); quickscroll(); }
  2189.     FreeMem( buffer, buflen );
  2190.     return 1;
  2191. }
  2192.  
  2193. static int
  2194. found( char *lstart, int lnum, int loffs, char *name, char left )
  2195. {
  2196.     int fileabort=0;
  2197.  
  2198.     if( (options&SEARCH_LEFT) && !left)
  2199.         return 0;
  2200.  
  2201.     if ( docr )
  2202.         { quickscroll(); printf("\n"); docr=0; }
  2203.  
  2204.     if( options&SEARCH_FILE ) {
  2205.         file_cr=1;
  2206.         if( !file_name )
  2207.             printf("%s",name), file_name=1;
  2208.         if( options&SEARCH_NUM )
  2209.             fileabort=1;
  2210.         else
  2211.             printf(" %d",lnum);
  2212.     } else if( options & SEARCH_BIN ) {
  2213.         if (!(options & SEARCH_NUM))
  2214.             printf("Byte offset %d\n",loffs);
  2215.         else
  2216.             printf("%d\n",loffs);
  2217.         quickscroll();
  2218.     } else {
  2219.         if (!(options & SEARCH_NUM))
  2220.             printf("%4d ",lnum);
  2221.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  2222.         quickscroll();
  2223.     }
  2224.     abort_search= options&SEARCH_ABORT;
  2225.     return dobreak() || fileabort || abort_search;
  2226. }
  2227.  
  2228. int
  2229. do_search( void )
  2230. {
  2231.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2232.     abort_search=0;
  2233.     searchstring=av[--ac];
  2234.     all_args(search_file, 0);
  2235.     return 0;
  2236. }
  2237.  
  2238. #if 0
  2239. /* do_grep() is just do_search() with a modified all_args() */
  2240. int
  2241. do_grep( void )
  2242. {
  2243.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2244.     abort_search=0;
  2245.     searchstring=av[1];
  2246.     all_args_n2m(search_file, 0, 2, ac);
  2247.     return 0;
  2248. }
  2249. #endif
  2250.  
  2251. static BOOL rm_error_abort = FALSE;
  2252. static int rm_file( long mask, char *file, char *fullpath )
  2253. {
  2254.     if (rm_error_abort)
  2255.         return(20);
  2256.  
  2257.     if ( *file && file[strlen(file)-1]=='/' ) {
  2258.         file[strlen(file)-1]=0;
  2259.     }
  2260.     if (options&16 || has_wild) {
  2261.         fprintf(stdout," %s....",fullpath);
  2262.         fflush(stdout);
  2263.     }
  2264.     if (options&2 || options&4) {
  2265.         setProtection(file,0L);
  2266.     }
  2267.     if (!DeleteFile(file)) {
  2268.         pError(file);
  2269.         if (options & 8) {
  2270.             rm_error_abort = TRUE;
  2271.             return 20;
  2272.         }
  2273.     } else if (options&16 || has_wild)
  2274.         fprintf(stdout,"Deleted\n");
  2275.  
  2276.     return 0;
  2277. }
  2278.  
  2279. int
  2280. do_rm( void )
  2281. {
  2282.     rm_error_abort = FALSE;
  2283.     all_args( rm_file, 1);
  2284.     rm_error_abort = FALSE;
  2285.     return 0;
  2286. }
  2287.  
  2288.  
  2289. int
  2290. do_history( void )
  2291. {
  2292.     HIST *hist;
  2293.     int i = H_tail_base;
  2294.     int len = av[1] ? strlen(av[1]) : 0;
  2295.     char buf[250];
  2296.  
  2297.     if( options&2 ) {
  2298.         while( safegets(buf,stdin) )
  2299.             add_history(buf);
  2300.         return 0;
  2301.     }
  2302.  
  2303.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  2304.         if (len == 0 || !strncmp(av[1], hist->line, len))
  2305.             if( options&1 )
  2306.                 printf("%s\n", hist->line);
  2307.             else
  2308.                 printf("%3d %s\n", i, hist->line);
  2309.     return 0;
  2310. }
  2311.  
  2312. int
  2313. do_mem( void )
  2314. {
  2315.     static ULONG clast, flast;
  2316.     ULONG cfree, ffree, clarg, flarg, i;
  2317.     char *desc="Free", *mem;
  2318.  
  2319.     if( options&32 )
  2320.         for( i=0; i<10; i++ )
  2321.             if(mem=(char*)AllocMem(0x7fffffff,0L))
  2322.                 FreeMem(mem,0x7fffffff);
  2323.  
  2324.     Forbid();
  2325.     cfree = AvailMem(MEMF_CHIP);
  2326.     ffree = AvailMem(MEMF_FAST);
  2327.     clarg = AvailMem(MEMF_CHIP|MEMF_LARGEST);
  2328.     flarg = AvailMem(MEMF_FAST|MEMF_LARGEST);
  2329.     Permit();
  2330.  
  2331.     if( options&8 ) {
  2332.         clast=cfree, flast=ffree;
  2333.         return 0;
  2334.     }
  2335.     if( options&16 )
  2336.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  2337.     if( options&4 ) {
  2338.         if     ( options & 1 ) printf("%lu\n",cfree);
  2339.         else if( options & 2 ) printf("%lu\n",ffree);
  2340.         else                   printf("%lu\n",cfree+ffree);
  2341.     } else {
  2342. #if 1
  2343.         if     ( options & 1 ) {
  2344.             printf("Free CHIP memory:%10s",itoa(cfree));
  2345.             if ( options&16 )
  2346.                 printf("\n");
  2347.             else
  2348.                 printf("    largest %10s\n",itoa(clarg));
  2349.         }
  2350.         else if( options & 2 ) {
  2351.             printf("Free FAST memory:%10s",itoa(ffree));
  2352.             if ( options&16 )
  2353.                 printf("\n");
  2354.             else
  2355.                 printf("    largest %10s\n",itoa(flarg));
  2356.         }
  2357.         else {
  2358.             if ( options&16 ) {
  2359.                 if (cfree)
  2360.                     printf("CHIP memory:%10s\n",itoa(cfree));
  2361.                 if (ffree)
  2362.                     printf("FAST memory:%10s\n",itoa(ffree));
  2363.             }
  2364.             else {
  2365.                 printf("CHIP memory:%10s",itoa(cfree));
  2366.                 printf("    largest%10s\n",itoa(clarg));
  2367.                 printf("FAST memory:%10s",itoa(ffree));
  2368.                 printf("    largest%10s\n",itoa(flarg));
  2369.             }
  2370.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  2371.         }
  2372. #else
  2373.         if     ( options & 1 ) printf("Free CHIP memory:%10s\n",itoa(cfree));
  2374.         else if( options & 2 ) printf("Free FAST memory:%10s\n",itoa(ffree));
  2375.         else {
  2376.             if(ffree) {
  2377.                 printf("CHIP memory:%10s\n",itoa(cfree));
  2378.                 printf("FAST memory:%10s\n",itoa(ffree));
  2379.             }
  2380.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  2381.         }
  2382. #endif
  2383.     }
  2384.     return 0;
  2385. }
  2386.  
  2387. int
  2388. do_forline( void )
  2389. {
  2390.     char vname[33], buf[256], *cstr;
  2391.     int lctr;
  2392.     FILE *f;
  2393.  
  2394.     strcpy(vname,av[1]);
  2395.     if( !strcmp(av[2],"STDIN") )
  2396.         f=stdin;
  2397.     else 
  2398.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  2399.  
  2400.     lctr=0;
  2401.     ++H_stack;
  2402.     cstr = compile_av (av, 3, ac, ' ', 0);
  2403.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  2404.         buf[strlen(buf)-1]='\0';    /* remove CR */
  2405.         lctr++;
  2406.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2407.         sprintf(buf,"%d",lctr);
  2408.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  2409.         exec_command(cstr);
  2410.     }
  2411.     if( f!=stdin ) fclose(f);
  2412.     --H_stack;
  2413.     free (cstr);
  2414.     if( lctr ) {
  2415.         unset_var (LEVEL_SET, vname);
  2416.         unset_var (LEVEL_SET, v_linenum);
  2417.     }
  2418.     return 0;
  2419. }
  2420.  
  2421. int
  2422. do_fornum( void )
  2423. {
  2424.     char vname[33], buf[16];
  2425.     int n1, n2, step, i=1, verbose, runs=0;
  2426.     char *cstr;
  2427.  
  2428.     verbose=(options & 1);
  2429.     strcpy(vname,av[i++]);
  2430.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2431.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2432.     if (options & 2) {
  2433.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2434.     } else
  2435.         step=1;
  2436.     ++H_stack;
  2437.     cstr = compile_av (av, i, ac, ' ', 0);
  2438.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  2439.          i+=step, runs++) {
  2440.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  2441.         sprintf(buf,"%d",i);
  2442.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2443.         exec_command(cstr);
  2444.     }
  2445.     --H_stack;
  2446.     free (cstr);
  2447.     if( runs )
  2448.         unset_var (LEVEL_SET, vname);
  2449.     return 0;
  2450. }
  2451.  
  2452. /*
  2453.  * foreach var_name  ( str str str str... str ) commands
  2454.  * spacing is important (unfortunately)
  2455.  *
  2456.  * ac=0    1 2 3 4 5 6 7
  2457.  * foreach i ( a b c ) echo $i
  2458.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  2459.  */
  2460.  
  2461. int
  2462. do_foreach( void )
  2463. {
  2464.     int cstart, cend;
  2465.     char *cstr, vname[33];
  2466.     char **fav;
  2467.     int i=1, verbose;
  2468.  
  2469.     verbose=(options & 1);
  2470.     strcpy(vname, av[i++]);
  2471.     if (*av[i] == '(') i++;
  2472.     cstart = i;
  2473.     while (i<ac && *av[i] != ')') i++;
  2474.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  2475.     ++H_stack;
  2476.     cend = i;
  2477.  
  2478.     fav = (char **)salloc(sizeof(char *) * (ac));
  2479.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  2480.  
  2481.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  2482.  
  2483.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd() && !breakchecke(); ++i) {
  2484.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  2485.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  2486.         execute(cstr);
  2487.     }
  2488.     --H_stack;
  2489.     free (fav);
  2490.     free (cstr);
  2491.     if( cstart<cend)
  2492.         unset_var (LEVEL_SET, vname);
  2493.     return 0;
  2494. }
  2495.  
  2496.  
  2497.  
  2498. int
  2499. do_forever( char *str )
  2500. {
  2501.     int rcode = 0;
  2502.     char *ptr = next_word( str );
  2503.  
  2504.     ++H_stack;
  2505.     for (;;) {
  2506.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  2507.         if (exec_command (ptr) > 0) {
  2508.             str = get_var(LEVEL_SET, v_lasterr);
  2509.             rcode = (str) ? atoi(str) : 20;
  2510.             break;
  2511.         }
  2512.     }
  2513.     --H_stack;
  2514.     return rcode;
  2515. }
  2516.  
  2517.  
  2518.  
  2519. extern struct IntuitionBase *IntuitionBase;
  2520.  
  2521. void wait_refresh(struct Window *window)
  2522. {
  2523.     if (window) {
  2524.         if (window->IDCMPFlags & IDCMP_CHANGEWINDOW) {
  2525.             struct IntuiMessage *msg;
  2526.             BOOL refreshed = FALSE;
  2527.             while (!refreshed) {
  2528.                 WaitPort(window->UserPort);
  2529.                 if (msg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
  2530.                     if (msg->Class == IDCMP_CHANGEWINDOW)
  2531.                         refreshed = TRUE;
  2532.                     ReplyMsg((struct Message *)msg);
  2533.                 }
  2534.             }
  2535.         }
  2536.     }
  2537. }
  2538.  
  2539. int do_window( void )
  2540. {
  2541. #if 1
  2542.     long x = -1, y = -1, w = -1, h = -1, maxwidth, maxheight;
  2543. #else
  2544.     long x = -1, y = -1, w = -1, h = -1, maxwidth, maxheight, arg[5];
  2545.     int i;
  2546. #endif
  2547.  
  2548.     if(options & 32) { /* -q */
  2549.         struct Screen *scrn;
  2550.         struct Window *window;
  2551.         ULONG ibase_lock;
  2552.         char **ibase_list=NULL;
  2553.         long i,ibase_num=0;
  2554.         char fmt[256];
  2555.  
  2556.         newwidth(); /**/    /* get current window width */
  2557.  
  2558.         ibase_lock = LockIBase(0);
  2559.  
  2560.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  2561.  
  2562.             struct List *list;
  2563.             struct Node *node;
  2564.             UBYTE PubNameBuf[MAXPUBSCREENNAME+4] = "";
  2565.  
  2566.             list = LockPubScreenList();
  2567.             for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  2568.                 if (((struct PubScreenNode *)node)->psn_Screen == scrn)
  2569.                     sprintf(PubNameBuf," [%s]",node->ln_Name);
  2570.             }
  2571.             UnlockPubScreenList();
  2572.  
  2573.             sprintf(fmt,"Screen %c%.*s%c%s (%d,%d,%dx%dx%d):\n",
  2574.                 scrn->Title ? '\"' : '(',
  2575.                 (options&64) ? 128 : (((w_width-36-strlen(PubNameBuf)) > 0) ? (w_width-36-strlen(PubNameBuf)) : 30),
  2576.                 scrn->Title ? scrn->Title : "no title",
  2577.                 scrn->Title ? '\"' : ')',
  2578.                 PubNameBuf,
  2579.                 scrn->LeftEdge,
  2580.                 scrn->TopEdge,
  2581.                 scrn->Width,
  2582.                 scrn->Height,
  2583.                 scrn->BitMap.Depth
  2584.             );
  2585.             add_array_list(&ibase_list,&ibase_num,fmt);
  2586.  
  2587.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  2588.                 sprintf(fmt,"   win %c%.*s%c (%d,%d,%dx%d)\n",
  2589.                     window->Title ? '\"' : '(',
  2590.                     (options&64) ? 128 : w_width-32,
  2591.                     window->Title ? window->Title : "no title",
  2592.                     window->Title ? '\"' : ')',
  2593.                     window->LeftEdge,
  2594.                     window->TopEdge,
  2595.                     window->Width,
  2596.                     window->Height
  2597.                 );
  2598.                 add_array_list(&ibase_list,&ibase_num,fmt);
  2599.             }
  2600.  
  2601.             if (scrn->NextScreen)
  2602.                 add_array_list(&ibase_list,&ibase_num,"\n");
  2603.         }
  2604.  
  2605.         UnlockIBase(ibase_lock);
  2606.  
  2607.         for(i=0; i<ibase_num; i++)
  2608.             printf("%s",ibase_list[i]);
  2609.  
  2610.         free_array_list(ibase_list,ibase_num);
  2611.  
  2612.         return 0;
  2613.     }
  2614.  
  2615.     if( o_nowindow || !Mywindow )
  2616.         return 20;
  2617.  
  2618.     maxwidth = Mywindow->WScreen->Width;
  2619.     maxheight= Mywindow->WScreen->Height;
  2620.  
  2621.     if( options&1 )
  2622.         x=Mywindow->LeftEdge,y=Mywindow->TopEdge,w=Mywindow->MinWidth,h=Mywindow->MinHeight;
  2623.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  2624.     if( options&4 ) WindowToFront(Mywindow);
  2625.     if( options&8 ) WindowToBack(Mywindow);
  2626.     if( options&16) ActivateWindow(Mywindow);
  2627.  
  2628.     if( ac == 5 ) {
  2629. #if 1
  2630.         x = myatoi(av[1],-2,maxwidth-Mywindow->MinWidth); if (atoierr) return 20;
  2631.         y = myatoi(av[2],-2,maxheight-Mywindow->MinHeight); if (atoierr) return 20;
  2632.         w = myatoi(av[3],-2,maxwidth); if (atoierr) return 20;
  2633.         h = myatoi(av[4],-2,maxheight); if (atoierr) return 20;
  2634. #else
  2635.         for(i=1; i<5; i++) {
  2636.             arg[i] = myatoi(av[i],-2,32767); if (atoierr) return 20;
  2637.         }
  2638.         x=arg[1]; y=arg[2]; w=arg[3]; h=arg[4];
  2639. #endif
  2640.  
  2641.         if (x == -1) x = 0;
  2642.         if (y == -1) y = 0;
  2643.         if (w == -1) w = maxwidth;
  2644.         if (h == -1) h = maxheight;
  2645.  
  2646.         if (x == -2) x = Mywindow->LeftEdge;
  2647.         if (y == -2) y = Mywindow->TopEdge;
  2648.         if (w == -2) w = Mywindow->Width;
  2649.         if (h == -2) h = Mywindow->Height;
  2650.     }
  2651.     else if ( ac != 1 ) {
  2652.         fprintf(stderr,"Usage: window <pos_x> <pos_y> <width> <height>\n");
  2653.         fprintf(stderr,"   or  window -<options>\n");
  2654.         return 20;
  2655.     }
  2656.  
  2657.     if( w != -1 ) {
  2658. #if 0
  2659.         int i;
  2660. #endif
  2661. #if 0
  2662.         if ( x+w>maxwidth || y+h>maxheight ) {
  2663.             ierror(NULL, 500);
  2664.             return 20;
  2665.         }
  2666. #endif
  2667.         if ( x+w>maxwidth )
  2668.             x = maxwidth - w;    /* alternatively: w=maxwidth-x; */
  2669.         if ( y+h>maxheight )
  2670.             y = maxheight - h;    /* alternatively: h=maxheight-y; */
  2671.         if( w<Mywindow->MinWidth )
  2672.             w = Mywindow->MinWidth;
  2673.         if( h<Mywindow->MinHeight )
  2674.             h = Mywindow->MinHeight;
  2675.  
  2676. #if 1
  2677.         if (Mywindow->IDCMPFlags & IDCMP_CHANGEWINDOW) {
  2678.             /* IDCMP_CHANGEWINDOW already recognized */
  2679.             ChangeWindowBox(Mywindow,x,y,w,h);
  2680.             wait_refresh(Mywindow);
  2681.         }
  2682.         else {
  2683.             /* make window recognize IDCMP_CHANGEWINDOW temporarily */
  2684.             ModifyIDCMP(Mywindow,Mywindow->IDCMPFlags|IDCMP_CHANGEWINDOW);
  2685.             ChangeWindowBox(Mywindow,x,y,w,h);
  2686.             wait_refresh(Mywindow);
  2687.             ModifyIDCMP(Mywindow,Mywindow->IDCMPFlags&(~IDCMP_CHANGEWINDOW));
  2688.         }
  2689. #else
  2690.         if( Mywindow->LeftEdge!=0 || Mywindow->TopEdge!=0 )
  2691.             MoveWindow(Mywindow, -Mywindow->LeftEdge, -Mywindow->TopEdge );
  2692.         if( Mywindow->Width!=w || Mywindow->Height!=h )
  2693.             SizeWindow(Mywindow, w-Mywindow->Width   , h-Mywindow->Height  );
  2694.         if( x || y )
  2695.             MoveWindow(Mywindow, x, y );
  2696. #endif
  2697.  
  2698. #if 0
  2699.         for( i=0; i<10; i++ ) {
  2700.             if(  Mywindow->LeftEdge==x && Mywindow->TopEdge==y &&
  2701.                  Mywindow->Width   ==w && Mywindow->Height ==h )
  2702.                 break;
  2703.             Delay(5);
  2704.         }
  2705. #endif
  2706.     }
  2707.  
  2708.     /* Delay(25); */ /* pause 1/2 sec. before trying to print */
  2709.     /* Delay(10); */
  2710.     /* printf("\014"); */
  2711.     return 0;
  2712. }
  2713.  
  2714.  
  2715.  
  2716. static void
  2717. setsystemtime(struct DateStamp *ds)
  2718. {
  2719.     struct timerequest tr;
  2720.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  2721.  
  2722.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  2723.         fprintf(stderr,"Clock error: can't open timer device\n");
  2724.         return;
  2725.     }
  2726.  
  2727.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  2728.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  2729.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  2730.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  2731.     tr.tr_node.io_Command = TR_SETSYSTIME;
  2732.     tr.tr_time.tv_secs = secs;
  2733.     tr.tr_time.tv_micro = 0L;
  2734.     if (DoIO ((struct IORequest *)&tr))
  2735.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  2736.     CloseDevice ((struct IORequest *)&tr);
  2737. }
  2738.  
  2739.  
  2740. static char tday[LEN_DATSTRING+1];    /* not sure, if +1 (null byte) is neccessary */
  2741.  
  2742. char *
  2743. dates( struct DateStamp *dss, int flags )
  2744. {
  2745.     static char timestr[2*LEN_DATSTRING+3];
  2746.     char tdate[LEN_DATSTRING+1], ttime[LEN_DATSTRING+1];
  2747.     struct DateTime dt;
  2748.     struct DateStamp *myds;
  2749.     char *dp,*tp;
  2750.     int slen;
  2751.  
  2752.     dt.dat_Format  = FORMAT_DOS;    /* bug in DOS, always localized :-( */
  2753.     dt.dat_StrDay  = tday;
  2754.     dt.dat_StrDate = tdate;
  2755.     dt.dat_StrTime = ttime;
  2756.     dt.dat_Flags   = flags ? DTF_SUBST : 0;
  2757.     dt.dat_Stamp   = *dss;
  2758.  
  2759.     myds = &(dt.dat_Stamp);
  2760.  
  2761.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  2762.          myds->ds_Minute<0 || myds->ds_Minute>1440 ||
  2763.          myds->ds_Tick<0   || myds->ds_Tick>3000 || !DateToStr(&dt) )
  2764.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  2765.  
  2766. #if 0
  2767.     ttime[8] = '\0';
  2768.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  2769. #endif
  2770.  
  2771.     /* strip off leading spaces from 'tdate' -> result in 'dp' */
  2772.  
  2773.     for (dp=tdate; dp && *dp && (*dp==' ' || *dp=='\t'); dp++)
  2774.         ;
  2775.  
  2776.     /* strip off trailing spaces from 'dp' */
  2777.  
  2778.     for (slen=strlen(dp)-1; slen>=0 && (dp[slen]==' ' || dp[slen]=='\t'); --slen)
  2779.         dp[slen] = '\0';
  2780.  
  2781.     /* strip off leading spaces from 'ttime' -> result in 'tp' */
  2782.  
  2783.     for (tp=ttime; tp && *tp && (*tp==' ' || *tp=='\t'); tp++)
  2784.         ;
  2785.  
  2786.     /* strip off trailing spaces from 'tp' */
  2787.  
  2788.     for (slen=strlen(tp)-1; slen>=0 && (tp[slen]==' ' || tp[slen]=='\t'); --slen)
  2789.         tp[slen] = '\0';
  2790.  
  2791.     /* month name > 3 chars? (bug in french locale) */
  2792.  
  2793.     while (strlen(dp) > 9)
  2794.         strdel(dp,6,1);
  2795.  
  2796.     sprintf(timestr,"%-9.9s %-8.8s",dp,tp);
  2797.  
  2798.     timestr[18] = '\0';    /* protection against bad timestamped files */
  2799.  
  2800.     return timestr;
  2801. }
  2802.  
  2803. /*
  2804.  * returns difference in msecs between two TIMEVALS (GMD)
  2805.  */
  2806.  
  2807. long tv_diff (struct timeval * tv1, struct timeval * tv2)
  2808. {
  2809.     long val;
  2810.  
  2811.     val = ((long) tv2->tv_secs - (long) tv1->tv_secs) * 1000L;
  2812.     val += (((long) tv2->tv_micro) - ((long) tv1->tv_micro)) / 1000L;
  2813.  
  2814.     return val;
  2815. }
  2816.  
  2817. /*
  2818.  * given a DateStamp structure , returns an updated TIMEVAL (GMD)
  2819.  */
  2820.  
  2821. void dss2tv (struct DateStamp * t1, struct timeval * tv)
  2822. {
  2823.     ULONG secs;
  2824.  
  2825.     secs = t1->ds_Days * 24 * 60 * 60;
  2826.     secs += t1->ds_Minute * 60;
  2827.     secs += t1->ds_Tick / TICKS_PER_SECOND;
  2828.  
  2829.     tv->tv_secs = secs;
  2830.     tv->tv_micro = (t1->ds_Tick % TICKS_PER_SECOND) * (1000000 / TICKS_PER_SECOND);
  2831. }
  2832.  
  2833. /*
  2834.  * tv2dss ; converts a timeval structure to a DateStamp structure (GMD)
  2835.  */
  2836.  
  2837. void tv2dss (struct timeval * tv, struct DateStamp * dss)
  2838. {
  2839.     long rem;
  2840.  
  2841.     dss->ds_Days = tv->tv_secs / (24 * 60 * 60);
  2842.     rem = tv->tv_secs % (24 * 60 * 60);    /* secs in last day */
  2843.  
  2844.     dss->ds_Minute = rem / 60;
  2845.     rem = rem % 60;        /* secs in last minute */
  2846.  
  2847.     rem = (rem * 1000) + (tv->tv_micro / 1000);    /* msecs in last minute */
  2848.  
  2849.     dss->ds_Tick = rem / (1000 / TICKS_PER_SECOND);    /* ticks in last minute */
  2850. }
  2851.  
  2852. /* code for battery-clock by Gary Duncan (GMD) */
  2853.  
  2854. int
  2855. do_date (void)
  2856. {
  2857.     static struct DateStamp dss_s; /* set by -s option */
  2858.     static struct timeval tv;
  2859.     struct DateStamp dss;
  2860.     struct DateTime dt;
  2861.     int i = 1;
  2862.  
  2863.     dt.dat_Format = FORMAT_DOS;
  2864.     if (ac == 1) {
  2865.         DateStamp(&dss);
  2866.         if (options & 4) {  /* its read-battery-clock time; GMD */
  2867.             struct timeval tv_batt;
  2868.             if (BattClockBase==NULL) {
  2869.                 fprintf(stderr,"No Battery Clock\n");
  2870.                 return 0;
  2871.             }
  2872.             tv_batt.tv_micro = 0;
  2873.             tv_batt.tv_secs  = ReadBattClock();
  2874.             tv2dss(&tv_batt,&dss);
  2875.         }
  2876.  
  2877.         if (options & 1) {        /* -s option */
  2878.             dss_s = dss;
  2879.             dss2tv(&dss_s,&tv);
  2880.         }
  2881.         else if (options & 2) {        /* -r option */
  2882.             long diff;
  2883.             struct timeval tv1;
  2884.  
  2885.             /*
  2886.              *  if -s not previous done , silently ignore
  2887.              */
  2888.             if (dss_s.ds_Days == 0)
  2889.                 return 0;
  2890.  
  2891.             dss2tv(&dss, &tv1);        /* current time */
  2892.             diff = tv_diff(&tv,&tv1);    /* diff in msecs */
  2893.  
  2894.             printf ("%d.%02d\n", diff / 1000, diff % 1000);
  2895.         }
  2896.         else
  2897.             printf ("%s %s\n", tday, dates (&dss, 0));
  2898.     }
  2899.     else {
  2900.         /* set the time here  */
  2901.         DateStamp (&dt.dat_Stamp);
  2902.         for (; i < ac; i++) {
  2903.             dt.dat_StrDate = NULL;
  2904.             dt.dat_StrTime = NULL;
  2905.             dt.dat_Flags = DTF_FUTURE;
  2906.             if (index (av[i], ':'))
  2907.                 dt.dat_StrTime = av[i];
  2908.             else
  2909.                 dt.dat_StrDate = av[i];
  2910.             if (!StrToDate (&dt))
  2911.                 ierror (av[i], 500);
  2912.         }
  2913.         setsystemtime (&(dt.dat_Stamp));
  2914.     }
  2915.     return 0;
  2916. }
  2917.  
  2918.